import json
import tempfile
import unittest
from pathlib import Path

from h8536.model import Instruction
from h8536.peripheral_access import analyze_peripheral_access, peripheral_comment_for_instruction
from h8536.render import write_json
from h8536.tables import IO_REGISTERS


class PeripheralAccessTest(unittest.TestCase):
    def test_frt1_manual_register_map_has_full_16_bit_pairs(self):
        self.assertEqual(IO_REGISTERS[0xFE94], "FRT1_OCRA_H")
        self.assertEqual(IO_REGISTERS[0xFE95], "FRT1_OCRA_L")
        self.assertEqual(IO_REGISTERS[0xFE98], "FRT1_ICR_H")

    def test_frt_word_access_is_marked_as_temp_safe(self):
        instructions = {
            0x1000: Instruction(
                0x1000,
                bytes.fromhex("1DFEA2051234"),
                "MOV:G.W",
                "#H'1234, @FRT2_FRC_H",
                references=[0xFEA2],
            ),
        }

        analysis = analyze_peripheral_access(instructions)

        self.assertIn("TEMP byte-order hazard avoided", peripheral_comment_for_instruction(analysis, 0x1000))
        self.assertEqual(analysis["warnings"], [])

    def test_low_byte_read_before_high_byte_warns(self):
        instructions = {
            0x1000: Instruction(
                0x1000,
                bytes.fromhex("15FEE105"),
                "MOV:G.B",
                "@ADDRA_L, R0",
                references=[0xFEE1],
            ),
        }

        analysis = analyze_peripheral_access(instructions)

        self.assertEqual(len(analysis["warnings"]), 1)
        self.assertIn("low byte read before matching high byte", analysis["warnings"][0]["message"])
        self.assertIn("check TEMP ordering", peripheral_comment_for_instruction(analysis, 0x1000))

    def test_ad_upper_byte_read_alone_is_allowed_for_8_bit_accuracy(self):
        instructions = {
            0x1000: Instruction(
                0x1000,
                bytes.fromhex("15FEE005"),
                "MOV:G.B",
                "@ADDRA_H, R0",
                references=[0xFEE0],
            ),
        }

        analysis = analyze_peripheral_access(instructions)

        self.assertEqual(analysis["warnings"], [])
        self.assertIn("valid 8-bit result", peripheral_comment_for_instruction(analysis, 0x1000))

    def test_json_includes_top_level_warnings_and_instruction_metadata(self):
        instructions = {
            0x1000: Instruction(
                0x1000,
                b"",
                "MOV:G.B",
                "@ADDRA_L, R0",
                references=[0xFEE1],
            ),
        }
        analysis = analyze_peripheral_access(instructions)

        with tempfile.TemporaryDirectory() as tmp:
            path = Path(tmp) / "out.json"
            write_json(path, instructions, {}, {}, peripheral_access=analysis)
            payload = json.loads(path.read_text(encoding="utf-8"))

        self.assertEqual(payload["peripheral_access"]["warnings"][0]["register"], "ADDRA")
        instruction = payload["instructions"][0]
        self.assertEqual(instruction["peripheral_access"][0]["register"], "ADDRA")


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