"""Unit tests for probe identity teach-in."""

from __future__ import annotations

import tempfile
import unittest
from pathlib import Path

from temp.identity import (
    ProbeMap,
    evaluate_identity,
    load_probe_map,
    save_probe_map,
)


class TestProbeMapPersistence(unittest.TestCase):
    def test_save_load_roundtrip(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            path = Path(tmp) / "probes.json"
            pm = ProbeMap(hot_in="28-h", tub=["28-a", "28-b", "28-c", "28-d"])
            save_probe_map(path, pm)
            loaded = load_probe_map(path)
            self.assertEqual(loaded.hot_in, "28-h")
            self.assertEqual(sorted(loaded.tub), sorted(pm.tub))


class TestEvaluateIdentity(unittest.TestCase):
    def test_one_probe_learns_hot_in(self) -> None:
        r = evaluate_identity(["28-hot"], ProbeMap(), setup_mode=True)
        self.assertTrue(r.map_changed)
        self.assertEqual(r.probe_map.hot_in, "28-hot")
        self.assertEqual(r.setup_state, "need_water")

    def test_four_alone_learns_tub_with_setup_mode(self) -> None:
        ids = [f"28-t{i}" for i in range(4)]
        r = evaluate_identity(ids, ProbeMap(), setup_mode=True)
        self.assertTrue(r.map_changed)
        self.assertEqual(sorted(r.probe_map.tub), sorted(ids))
        self.assertEqual(r.setup_state, "need_hot_in")

    def test_five_empty_map_need_reinstall(self) -> None:
        ids = [f"28-x{i}" for i in range(5)]
        r = evaluate_identity(ids, ProbeMap(), setup_mode=True)
        self.assertFalse(r.map_changed)
        self.assertEqual(r.setup_state, "need_reinstall")

    def test_five_derive_tub_when_hot_known(self) -> None:
        hot = "28-hot"
        tubs = [f"28-t{i}" for i in range(4)]
        pm = ProbeMap(hot_in=hot, tub=[])
        r = evaluate_identity([hot, *tubs], pm, setup_mode=False)
        self.assertTrue(r.map_changed)
        self.assertEqual(sorted(r.probe_map.tub), sorted(tubs))
        self.assertEqual(r.setup_state, "ready")

    def test_five_derive_hot_when_tub_known(self) -> None:
        hot = "28-hot"
        tubs = [f"28-t{i}" for i in range(4)]
        pm = ProbeMap(hot_in=None, tub=tubs)
        r = evaluate_identity([hot, *tubs], pm, setup_mode=False)
        self.assertTrue(r.map_changed)
        self.assertEqual(r.probe_map.hot_in, hot)
        self.assertEqual(r.setup_state, "ready")

    def test_four_mixed_does_not_mislearn_when_hot_on_bus(self) -> None:
        hot = "28-hot"
        pm = ProbeMap(hot_in=hot, tub=[])
        # hot + 3 tub = 4 devices — must not assign all 4 as tub
        r = evaluate_identity([hot, "28-t1", "28-t2", "28-t3"], pm, setup_mode=True)
        self.assertFalse(r.map_changed)
        self.assertEqual(r.probe_map.tub, [])

    def test_complete_map_no_overwrite_on_single_probe(self) -> None:
        pm = ProbeMap(hot_in="28-h", tub=[f"28-t{i}" for i in range(4)])
        r = evaluate_identity(["28-h"], pm, setup_mode=False)
        self.assertFalse(r.map_changed)
        self.assertEqual(r.setup_state, "ready")


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