"""Light (torch-free) emotion engine tests — the erable-deployable V/A path."""
import sys
import tempfile

import numpy as np
import soundfile as sf

import config
from engines import ears_light


def _tone(freqs, sr=22050, secs=2.0, amp=0.2, noise=0.0):
    t = np.linspace(0, secs, int(sr * secs), endpoint=False)
    y = sum(amp * np.sin(2 * np.pi * f * t) for f in freqs)
    if noise:
        y = y + noise * np.random.default_rng(0).standard_normal(y.shape)
    f = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
    sf.write(f.name, y.astype("float32"), sr)
    return f.name


def test_anchors_match_ontology():
    # drift guard: the duplicated V/A anchors must equal emotion_ontology.EMOTIONS
    sys.path.insert(0, str(config.TIDE_TABLE))
    import emotion_ontology as EMO
    truth = {n: (v, a) for n, (v, a, _) in EMO.EMOTIONS.items()}
    assert ears_light.ANCHORS == truth


def test_mode_valence_major_beats_minor():
    # C major triad (C E G) vs C minor triad (C Eb G) as idealized chroma
    major = np.zeros(12); major[[0, 4, 7]] = 1.0
    minor = np.zeros(12); minor[[0, 3, 7]] = 1.0
    assert ears_light._mode_valence(major) > ears_light._mode_valence(minor)


def test_emotion_light_shape_and_range():
    r = ears_light.emotion_light(_tone([220, 440]))
    assert -1 <= r["valence"] <= 1 and -1 <= r["arousal"] <= 1
    assert r["engine"] == "light"
    assert len(r["top"]) == 12 and isinstance(r["top"][0][0], str)
    assert abs(sum(p for _, p in r["top"]) - 1.0) < 1e-3   # dist sums to 1


def test_arousal_orders_energetic_above_calm():
    calm = ears_light.emotion_light(_tone([110], amp=0.05))            # quiet, low, pure
    hot = ears_light.emotion_light(_tone([440, 880], amp=0.3, noise=0.2))  # loud, bright, noisy
    assert hot["arousal"] > calm["arousal"]


def test_endpoint_light_path_is_torch_free(monkeypatch):
    # Prove /analyze/emotion works end-to-end with NO CLAP/torch, the erable path.
    monkeypatch.setattr(config, "EMOTION_ENGINE", "light")
    from fastapi.testclient import TestClient
    import app as APP
    client = TestClient(APP.app)

    wav = _tone([330, 660])
    with open(wav, "rb") as fh:
        data = fh.read()
    r = client.post("/analyze/emotion",
                    files={"file": ("t.wav", data, "audio/wav")},
                    headers={"X-Tenant": "hexa", "X-Scopes": "api:audio:*"})
    assert r.status_code == 200
    body = r.json()
    assert body["emotion"]["engine"] == "light"
    assert -1 <= body["emotion"]["valence"] <= 1
