from __future__ import annotations

import numpy as np

from evaluation.metrics import (
    orthogonality_check,
    phase_alignment_score,
    temporal_consistency,
)
from cognitive_signal.models.types import Phase, SignalVector, TemporalSignal


def _signal(
    *,
    valence: float,
    arousal: float,
    agency: float,
    self_focus: float,
    social_orientation: float,
    action_ratio: float,
) -> SignalVector:
    return SignalVector(
        embedding=np.zeros(384, dtype=np.float32),
        valence=valence,
        arousal=arousal,
        agency=agency,
        self_focus=self_focus,
        social_orientation=social_orientation,
        action_ratio=action_ratio,
    )


def test_orthogonality_check_returns_matrix_and_violations() -> None:
    vectors = [
        _signal(
            valence=i / 20.0,
            arousal=((i % 4) / 4.0),
            agency=(i / 20.0) * 0.9 + 0.05,
            self_focus=((20 - i) / 20.0),
            social_orientation=((i * 3) % 7) / 7.0,
            action_ratio=((i * 5) % 9) / 9.0,
        )
        for i in range(1, 21)
    ]

    report = orthogonality_check(vectors)

    corr = report["correlation_matrix"]
    assert corr.shape == (6, 6)
    assert np.allclose(np.diag(corr), 1.0)
    assert any(
        (left == "valence" and right == "agency")
        or (left == "agency" and right == "valence")
        for left, right, _ in report["violations"]
    )


def test_temporal_consistency_flags_invalid_values() -> None:
    temporal_signals = {
        "valence": [
            TemporalSignal(delta=0.0, trend=0.01, volatility=0.1, persistence=0.5),
            TemporalSignal(delta=float("nan"), trend=0.0, volatility=0.1, persistence=0.2),
        ],
        "arousal": [
            TemporalSignal(delta=0.1, trend=-0.01, volatility=-0.2, persistence=1.2),
        ],
    }

    report = temporal_consistency(temporal_signals)

    assert report["is_valid"] is False
    assert report["checked_points"] == 3
    assert len(report["issues"]) >= 2


def test_phase_alignment_score_perfect_and_shifted() -> None:
    ground_truth = [
        Phase(start=0, end=19, phase_id=0),
        Phase(start=20, end=39, phase_id=1),
        Phase(start=40, end=59, phase_id=2),
    ]
    perfect = [
        Phase(start=0, end=19, phase_id=10),
        Phase(start=20, end=39, phase_id=11),
        Phase(start=40, end=59, phase_id=12),
    ]
    shifted = [
        Phase(start=0, end=24, phase_id=0),
        Phase(start=25, end=44, phase_id=1),
        Phase(start=45, end=59, phase_id=2),
    ]

    assert phase_alignment_score(perfect, ground_truth) == 1.0
    shifted_score = phase_alignment_score(shifted, ground_truth)
    assert 0.0 <= shifted_score < 1.0
