import json
import tempfile
import unittest
from pathlib import Path
from bot.lib import state


class TestState(unittest.TestCase):
    def setUp(self):
        self.tmp = Path(tempfile.mkdtemp())

    def test_load_returns_empty_when_missing(self):
        self.assertEqual(state.load_last_seen(self.tmp / "missing.json"), {})

    def test_save_then_load_roundtrip(self):
        path = self.tmp / "s.json"
        data = {"wow": {"build": 110207, "version": "11.2.7", "seen_at": "2026-05-06T00:00:00Z"}}
        state.save_last_seen(path, data)
        self.assertEqual(state.load_last_seen(path), data)

    def test_save_is_atomic_via_tmp_then_replace(self):
        path = self.tmp / "s.json"
        state.save_last_seen(path, {"wow": {"build": 1, "version": "x", "seen_at": "y"}})
        self.assertTrue(path.exists())
        self.assertFalse((self.tmp / "s.json.tmp").exists())

    def test_kill_switch_present(self):
        (self.tmp / "disabled").touch()
        self.assertTrue(state.is_disabled(self.tmp))

    def test_kill_switch_absent(self):
        self.assertFalse(state.is_disabled(self.tmp))

    def test_failure_counter_increment_and_reset(self):
        state.bump_failure(self.tmp)
        state.bump_failure(self.tmp)
        self.assertEqual(state.read_failure_count(self.tmp), 2)
        state.reset_failures(self.tmp)
        self.assertEqual(state.read_failure_count(self.tmp), 0)

    def test_pending_fixes_empty_when_missing(self):
        self.assertEqual(state.load_pending_fixes(self.tmp), {})

    def test_record_pending_fix_then_load(self):
        entry = {
            "report_path": "bot/reports/x.md",
            "status": "auto-ship-eligible",
            "confidence": 88,
            "worktree_path": "/tmp/wt",
            "created_at": "2026-05-07T11:24:18Z",
            "verify_rows": [],
            "rationale": "ok",
        }
        state.record_pending_fix(self.tmp, "bot/patch-x", entry)
        loaded = state.load_pending_fixes(self.tmp)
        self.assertEqual(loaded["bot/patch-x"], entry)

    def test_remove_pending_fix(self):
        state.record_pending_fix(self.tmp, "bot/a", {"status": "held-for-review"})
        state.record_pending_fix(self.tmp, "bot/b", {"status": "auto-ship-eligible"})
        state.remove_pending_fix(self.tmp, "bot/a")
        loaded = state.load_pending_fixes(self.tmp)
        self.assertNotIn("bot/a", loaded)
        self.assertIn("bot/b", loaded)

    def test_remove_pending_fix_missing_is_noop(self):
        state.remove_pending_fix(self.tmp, "bot/never-existed")
        self.assertEqual(state.load_pending_fixes(self.tmp), {})

    def test_pending_releases_empty_when_missing(self):
        self.assertEqual(state.load_pending_releases(self.tmp), {})

    def test_record_pending_release_then_load(self):
        entry = {
            "branch": "wow",
            "tag": "v5.5.8",
            "scheduled_at": "2026-05-12T09:14:23.456-07:00",
            "status": "scheduled",
            "fix_branch": "bot/patch-wow-12_0_5",
            "report_path": "bot/reports/x.md",
            "created_at": "2026-05-07T11:24:18Z",
            "retries": 0,
        }
        state.record_pending_release(self.tmp, "v5.5.8", entry)
        loaded = state.load_pending_releases(self.tmp)
        self.assertEqual(loaded["v5.5.8"], entry)

    def test_remove_pending_release(self):
        state.record_pending_release(self.tmp, "v5.5.8", {"status": "scheduled"})
        state.record_pending_release(self.tmp, "v5.5.9", {"status": "scheduled"})
        state.remove_pending_release(self.tmp, "v5.5.8")
        loaded = state.load_pending_releases(self.tmp)
        self.assertNotIn("v5.5.8", loaded)
        self.assertIn("v5.5.9", loaded)

    def test_remove_pending_release_missing_is_noop(self):
        state.remove_pending_release(self.tmp, "v9.9.9")
        self.assertEqual(state.load_pending_releases(self.tmp), {})


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