#!/usr/bin/env python3
"""Unit tests do decoder Viterbi (sem rede, sem workdir)."""
import unittest
import storyboard_viterbi as SV


class TestViterbi(unittest.TestCase):
    def test_clamp_unknown(self):
        self.assertEqual(SV.clamp_beat("nope"), "officiant")
        self.assertEqual(SV.clamp_beat("vows"), "vows")

    def test_monotonic_phases_clean_ceremony(self):
        # 8 janelas com votos limpos na ordem canônica
        votes = [
            ["pre", "pre", "pre"],
            ["entrance_groom", "entrance_groom", "entrance_mother"],
            ["entrance_bride", "entrance_bride", "entrance_bride"],
            ["vows", "officiant", "vows"],
            ["vows", "vows", "reading"],
            ["rings", "rings", "rings"],
            ["declaration", "kiss", "kiss"],
            ["exit", "applause", "exit"],
        ]
        phases = SV.viterbi_phases(votes)
        self.assertEqual(phases[0], "pre")
        self.assertEqual(phases[1], "entrances")
        self.assertEqual(phases[2], "entrances")
        self.assertIn(phases[3], ("liturgia", "entrances"))  # pode ainda estar em entrances se emissoes fracas
        # última deve ser exit ou applause
        self.assertIn(phases[-1], ("exit", "applause", "kiss", "declaration"))

    def test_rejects_early_exit_noise(self):
        # votes ruidosos com exit no meio de votos — decoder deve preferir liturgia
        votes = [
            ["entrance_bride"] * 3,
            ["vows", "vows", "exit"],  # exit falso
            ["vows", "officiant", "vows"],
            ["rings"] * 3,
            ["kiss"] * 3,
            ["exit"] * 3,
        ]
        phases = SV.viterbi_phases(votes)
        # janela 1 (índice 1) não deve ser exit
        self.assertNotEqual(phases[1], "exit")
        self.assertIn(phases[-1], ("exit", "applause", "kiss"))

    def test_decode_windows_importance_from_table(self):
        # sequência longa o bastante p/ o prior monotônico chegar em kiss
        votes = (
            [["entrance_bride"] * 3]
            + [["vows"] * 3] * 2
            + [["rings"] * 3]
            + [["declaration"] * 3]
            + [["kiss"] * 3]
        )
        emos = [["high"] * 3] * len(votes)
        out = SV.decode_windows(votes, emos)
        self.assertEqual(out[0]["beat"], "entrance_bride")
        self.assertGreaterEqual(out[0]["importance"], 0.85)
        self.assertEqual(out[-1]["beat"], "kiss")
        self.assertEqual(out[-1]["phase"], "kiss")

    def test_eval_sequence_targets(self):
        segs = [
            {"f0": 0, "f1": 100, "beat": "pre"},
            {"f0": 100, "f1": 200, "beat": "entrance_groom"},
            {"f0": 200, "f1": 300, "beat": "entrance_bride"},
            {"f0": 300, "f1": 800, "beat": "vows"},
            {"f0": 800, "f1": 900, "beat": "rings"},
            {"f0": 900, "f1": 950, "beat": "kiss"},
            {"f0": 950, "f1": 1000, "beat": "exit"},
        ]
        m = SV.eval_sequence(segs, 0, 1000)
        self.assertTrue(m["pass_decl_before"])
        self.assertTrue(m["pass_exit_early"])
        self.assertEqual(m["entrance_bride_count"], 1)

    def test_merge_same_beat(self):
        rows = [
            {"f0": 0, "f1": 100, "beat": "vows", "importance": 0.8, "emotion": "low"},
            {"f0": 100, "f1": 200, "beat": "vows", "importance": 0.9, "emotion": "high"},
            {"f0": 200, "f1": 300, "beat": "kiss", "importance": 0.9, "emotion": "high"},
        ]
        m = SV.merge_same_beat(rows)
        self.assertEqual(len(m), 2)
        self.assertEqual(m[0]["f1"], 200)
        self.assertEqual(m[0]["emotion"], "high")


if __name__ == "__main__":
    unittest.main()
