import json
import numpy as np
import pytest

from database import db as motion_db
from pipeline.svd_pipeline import (
    _safe_k,
    _build_vote_matrix,
    _procrustes_align,
    run_svd_for_window,
)


def test_safe_k_and_build_and_run(tmp_path):
    np.random.seed(0)
    # reset DB file for test
    db_path = tmp_path / "test.db"
    # point the MotionDatabase to this test DB
    motion_db.db_path = str(db_path)
    motion_db._init_database()

    # Create synthetic dataset: 5 MPs x 6 motions
    mps = [f"MP_{i}" for i in range(5)]
    motions = list(range(100, 106))
    dates = ["2020-01-0" + str(i + 1) for i in range(6)]

    votes = ["Voor", "Tegen", "Geen stem"]

    # insert votes: fill full matrix using MotionDatabase helper
    for j, motion_id in enumerate(motions):
        for i, mp in enumerate(mps):
            vote = votes[(i + j) % len(votes)]
            motion_db.insert_mp_vote(motion_id, mp, vote, date=dates[j])

    mat, mp_names, motion_ids = _build_vote_matrix(
        motion_db, "2020-01-01", "2020-01-10"
    )
    assert mat.shape == (5, 6)

    # _safe_k: with k=10 -> min_dim=5 -> returns 4
    assert _safe_k(mat, 10) == 4
    assert _safe_k(mat, 3) == 3

    # run_svd_for_window with k=10 -> should use k_used=4
    res = run_svd_for_window(motion_db, "w1", "2020-01-01", "2020-01-10", k=10)
    assert res["k_used"] == 4
    assert res["stored_mp"] == 5
    assert res["stored_motion"] == 6


def test_procrustes_align():
    np.random.seed(0)
    # create reference anchors and current anchors rotated + noise
    ref = np.random.randn(10, 3)
    # create orthogonal rotation
    Q, _ = np.linalg.qr(np.random.randn(3, 3))
    cur = ref.dot(Q) + 0.1 * np.random.randn(10, 3)

    before = np.linalg.norm(cur - ref)
    transformed = _procrustes_align(ref, cur)
    after = np.linalg.norm(transformed - ref)

    assert after < before
