"""Everything the page does to a room, in one call: embed, normalise, PCA, t-SNE, cluster, name, measure.

    python -m roommap.pipeline            # runs the built-in sample room and prints the result as JSON
"""
from __future__ import annotations

import json
import sys
import time

import numpy as np

from . import cluster, embed, metrics, pca, tsne
from .sample import SAMPLE


def nearest(X: np.ndarray, i: int, k: int = 5) -> list[tuple[int, float]]:
    """The k most similar rows to row i by cosine (rows are unit vectors), as (index, similarity)."""
    sims = X @ X[i]
    order = sorted(((-float(sims[j]), j) for j in range(X.shape[0]) if j != i))
    return [(j, -s) for s, j in order[:k]]


def run(texts: list[str], vectors: np.ndarray | None = None, seed: int = 1, iters: int = tsne.ITERS) -> dict:
    t0 = time.perf_counter()
    X = embed.embed_all(texts) if vectors is None else np.asarray(vectors, dtype=float)
    X = pca.normalise_rows(X)
    t1 = time.perf_counter()
    pcs, explained = pca.pca(X, 10)
    t2 = time.perf_counter()
    Y, kl = tsne.layout(pcs, iters=iters)
    t3 = time.perf_counter()
    k, labels, scores = cluster.choose_k(pcs, seed=seed)
    names = cluster.name_clusters(texts, labels)
    t4 = time.perf_counter()
    return {
        "n": len(texts),
        "embedder": embed.EMBEDDER_ID,
        "vectors": X,
        "pcs": pcs,
        "explained": explained,
        "layout": Y,
        "kl": kl,
        "k": k,
        "labels": labels,
        "names": names,
        "silhouettes": scores,
        "trustworthiness": metrics.trustworthiness(pcs, Y, 5),
        "preservation": metrics.neighbourhood_preservation(pcs, Y, 5),
        "trust_vs_embedding": metrics.trustworthiness(X, Y, 5),
        "timing_ms": {"embed": (t1 - t0) * 1e3, "pca": (t2 - t1) * 1e3, "tsne": (t3 - t2) * 1e3, "cluster": (t4 - t3) * 1e3},
    }


def to_json(res: dict) -> dict:
    out = {}
    for k, v in res.items():
        out[k] = v.tolist() if isinstance(v, np.ndarray) else v
    return out


if __name__ == "__main__":
    texts = SAMPLE
    if len(sys.argv) > 1:
        texts = [line.strip() for line in open(sys.argv[1], encoding="utf-8") if line.strip()]
    print(json.dumps(to_json(run(texts))))
