from __future__ import annotations

import numpy as np

from cognitive_signal.dissonance.detector import DissonanceDetector
from cognitive_signal.models.types import SignalVector


def _signal(
    *,
    embedding: np.ndarray | None = None,
    valence: float = 0.0,
    arousal: float = 0.5,
    agency: float = 0.5,
    self_focus: float = 0.5,
    social_orientation: float = 0.5,
    action_ratio: float = 0.5,
) -> SignalVector:
    return SignalVector(
        embedding=embedding
        if embedding is not None
        else 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_repeated_independence_statement_triggers_social_and_protest() -> None:
    detector = DissonanceDetector()
    phrase = "I don't need anyone, I'm completely fine on my own"
    text = " ".join([phrase] * 5)
    current = _signal(
        embedding=np.ones(384, dtype=np.float32),
        valence=0.92,
        arousal=0.46,
        agency=0.55,
        self_focus=0.72,
        social_orientation=0.05,
        action_ratio=0.45,
    )
    recent = [
        _signal(
            embedding=np.ones(384, dtype=np.float32) + (i * 1e-4),
            valence=0.9,
            arousal=0.45,
            agency=0.5,
            self_focus=0.68,
            social_orientation=0.07,
            action_ratio=0.4,
        )
        for i in range(5)
    ]

    output = detector.detect(current, recent_signals=recent, text=text)

    assert output.social_isolation_conflict > 0.7
    assert output.protest_positivity > 0.6


def test_passive_agency_talk_high_when_agency_high_action_low() -> None:
    detector = DissonanceDetector()
    signal = _signal(
        embedding=np.full(384, 0.3, dtype=np.float32),
        valence=0.2,
        arousal=0.5,
        agency=0.85,
        self_focus=0.5,
        social_orientation=0.5,
        action_ratio=0.2,
    )
    output = detector.detect(
        signal, recent_signals=None, text="I decided to take charge of my life"
    )
    assert output.passive_agency_talk > 0.6


def test_normal_healthy_entry_low_dissonance_all_rules() -> None:
    detector = DissonanceDetector()
    current = _signal(
        embedding=np.concatenate(
            [
                np.ones(192, dtype=np.float32),
                np.zeros(192, dtype=np.float32),
            ]
        ),
        valence=0.2,
        arousal=0.55,
        agency=0.45,
        self_focus=0.35,
        social_orientation=0.62,
        action_ratio=0.58,
    )
    recent = [
        _signal(
            embedding=np.concatenate(
                [
                    np.zeros(192, dtype=np.float32),
                    np.ones(192, dtype=np.float32),
                ]
            ),
            valence=0.1,
            arousal=0.35,
            agency=0.4,
            self_focus=0.35,
            social_orientation=0.65,
            action_ratio=0.6,
        ),
        _signal(
            embedding=np.eye(1, 384, 0, dtype=np.float32).reshape(-1),
            valence=0.35,
            arousal=0.7,
            agency=0.55,
            self_focus=0.4,
            social_orientation=0.55,
            action_ratio=0.5,
        ),
        _signal(
            embedding=np.eye(1, 384, 1, dtype=np.float32).reshape(-1),
            valence=0.45,
            arousal=0.45,
            agency=0.5,
            self_focus=0.42,
            social_orientation=0.58,
            action_ratio=0.57,
        ),
        _signal(
            embedding=np.eye(1, 384, 2, dtype=np.float32).reshape(-1),
            valence=0.2,
            arousal=0.6,
            agency=0.46,
            self_focus=0.36,
            social_orientation=0.61,
            action_ratio=0.59,
        ),
    ]
    text = (
        "I felt mixed emotions because the day was complex, although I learned "
        "useful lessons and might adjust my approach tomorrow."
    )
    output = detector.detect(current, recent_signals=recent, text=text)

    assert output.protest_positivity < 0.3
    assert output.passive_agency_talk < 0.3
    assert output.social_isolation_conflict < 0.3
    assert output.forced_calm < 0.3
    assert output.overall_dissonance < 0.3


def test_scores_are_bounded() -> None:
    detector = DissonanceDetector()
    current = _signal(
        embedding=np.ones(384, dtype=np.float32),
        valence=1.0,
        arousal=0.0,
        agency=1.0,
        self_focus=1.0,
        social_orientation=0.0,
        action_ratio=0.0,
    )
    recent = [
        _signal(
            embedding=np.ones(384, dtype=np.float32) + (i * 1e-5),
            valence=1.0,
            arousal=0.0,
            agency=1.0,
            self_focus=1.0,
            social_orientation=0.0,
            action_ratio=0.0,
        )
        for i in range(6)
    ]
    text = "I definitely always know nobody understands me and I am absolutely fine."
    output = detector.detect(current, recent_signals=recent, text=text)

    assert 0.0 <= output.protest_positivity <= 1.0
    assert 0.0 <= output.passive_agency_talk <= 1.0
    assert 0.0 <= output.social_isolation_conflict <= 1.0
    assert 0.0 <= output.forced_calm <= 1.0
    assert 0.0 <= output.overall_dissonance <= 1.0


def test_missing_text_and_history_are_conservative() -> None:
    detector = DissonanceDetector()
    current = _signal(
        embedding=np.ones(384, dtype=np.float32),
        valence=0.95,
        arousal=0.15,
        agency=0.3,
        self_focus=0.9,
        social_orientation=0.0,
        action_ratio=0.5,
    )
    output = detector.detect(current, recent_signals=None, text=None)

    assert output.forced_calm == 0.0
    assert output.social_isolation_conflict <= 0.4
    assert output.protest_positivity <= 0.35
