from __future__ import annotations

import unittest

from backend.features.heaven.six_yao import (
    _palace_map,
    build_six_yao_chart,
)


class SixYaoEngineTests(unittest.TestCase):
    def test_eight_palaces_cover_every_hexagram_once(self):
        palaces = _palace_map()

        self.assertEqual(len(palaces), 64)
        self.assertEqual(
            {item["trigram"] for item in palaces.values()},
            {"乾", "兑", "离", "震", "巽", "坎", "艮", "坤"},
        )
        self.assertEqual(
            {item["stage"] for item in palaces.values()},
            {"本宫", "一世", "二世", "三世", "四世", "五世", "游魂", "归魂"},
        )

    def test_pure_qian_uses_standard_najia_and_self_response(self):
        chart = build_six_yao_chart(
            [7, 7, 7, 7, 7, 7],
            "2026-08-04T10:30:00+08:00",
        )

        self.assertEqual(chart["palace"]["name"], "乾宫")
        self.assertEqual(chart["palace"]["stage"], "本宫")
        self.assertEqual(chart["palace"]["self_position"], 6)
        self.assertEqual(chart["palace"]["response_position"], 3)
        self.assertEqual(
            [(line["stem"], line["branch"]) for line in chart["lines"]],
            [("甲", "子"), ("甲", "寅"), ("甲", "辰"), ("壬", "午"), ("壬", "申"), ("壬", "戌")],
        )
        self.assertEqual(
            [line["relative"] for line in chart["lines"]],
            ["子孙", "妻财", "父母", "官鬼", "兄弟", "父母"],
        )
        self.assertEqual(chart["branch_pattern"], "六冲")

    def test_pure_kun_uses_standard_najia(self):
        chart = build_six_yao_chart(
            [8, 8, 8, 8, 8, 8],
            "2026-08-04T10:30:00+08:00",
        )

        self.assertEqual(chart["palace"]["name"], "坤宫")
        self.assertEqual(
            [(line["stem"], line["branch"]) for line in chart["lines"]],
            [("乙", "未"), ("乙", "巳"), ("乙", "卯"), ("癸", "丑"), ("癸", "亥"), ("癸", "酉")],
        )

    def test_cast_time_drives_day_void_and_six_spirits(self):
        chart = build_six_yao_chart(
            [7, 7, 7, 7, 7, 7],
            "2026-08-04T02:30:00Z",
        )

        self.assertEqual(chart["cast_at"], "2026-08-04T10:30:00+08:00")
        self.assertEqual(chart["calendar"]["day"], "庚戌")
        self.assertEqual(chart["calendar"]["day_void"], "寅卯")
        self.assertEqual(
            [line["spirit"] for line in chart["lines"]],
            ["白虎", "玄武", "青龙", "朱雀", "勾陈", "螣蛇"],
        )

    def test_moving_line_has_deterministic_transformation(self):
        chart = build_six_yao_chart(
            [6, 7, 8, 9, 7, 8],
            "2026-08-04T10:30:00+08:00",
        )

        moving = [line for line in chart["lines"] if line["moving"]]
        self.assertEqual([line["position"] for line in moving], [1, 4])
        self.assertTrue(all(line.get("transformation") for line in moving))
        self.assertFalse(any(line.get("transformation") for line in chart["lines"] if not line["moving"]))


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