import json
import unittest

from h8536.board_profile import analyze_board_profile, board_comment_for_instruction, board_json_payload
from h8536.model import Instruction


def ins(address: int, mnemonic: str, operands: str, references: list[int]) -> Instruction:
    return Instruction(address, b"\x00", mnemonic, operands, references=references)


class BoardProfileTest(unittest.TestCase):
    def test_profile_records_manual_pin_table_and_board_traces(self):
        analysis = analyze_board_profile({})

        self.assertEqual(analysis["board"], "sony_rcp_tx7")
        self.assertIn("Manual/0900766b802125d0.md:2417", " ".join(analysis["manual_references"]))
        self.assertIn("Manual/0900766b802125d0.md:2418", " ".join(analysis["manual_references"]))
        traces = analysis["traces"]
        self.assertEqual(traces[0]["h8_pin"], 66)
        self.assertEqual(traces[0]["max202_pin"], 11)
        self.assertEqual(traces[1]["h8_pin"], 67)
        self.assertEqual(traces[1]["max202_pin"], 12)
        self.assertEqual(board_json_payload(analysis)["board"], "sony_rcp_tx7")
        json.dumps(analysis)

    def test_sci1_init_and_scr_comments_identify_rs232_max202_path(self):
        instructions = {
            0x1000: ins(0x1000, "MOV:G.W", "#H'0407, @SCI1_SMR", [0xFED8]),
            0x1004: ins(0x1004, "MOV:G.B", "#H'30, @SCI1_SCR", [0xFEDA]),
        }

        analysis = analyze_board_profile(instructions)

        self.assertIn("SCI1 SMR serial init for traced RS232/MAX202 path", board_comment_for_instruction(analysis, 0x1000))
        self.assertIn("SCI1 BRR serial init for traced RS232/MAX202 path", board_comment_for_instruction(analysis, 0x1000))
        scr_comment = board_comment_for_instruction(analysis, 0x1004)
        self.assertIn("SCI1 SCR write TE=1 RE=1", scr_comment)
        self.assertIn("P95/TXD pin 66 to MAX202 pin 11", scr_comment)
        self.assertIn("P96/RXD pin 67 to MAX202 pin 12", scr_comment)

    def test_sci1_data_and_status_registers_annotate_traced_path(self):
        instructions = {
            0x1010: ins(0x1010, "BTST.B", "#7, @SCI1_SSR", [0xFEDC]),
            0x1012: ins(0x1012, "MOV:G.B", "R0L, @SCI1_TDR", [0xFEDB]),
            0x1014: ins(0x1014, "MOV:G.B", "@SCI1_RDR, R0L", [0xFEDD]),
        }

        analysis = analyze_board_profile(instructions)

        self.assertIn("SCI1 SSR status for traced RS232/MAX202 path", board_comment_for_instruction(analysis, 0x1010))
        self.assertIn("H8 pin 66 P95/TXD -> MAX202 pin 11", board_comment_for_instruction(analysis, 0x1012))
        self.assertIn("MAX202 pin 12 -> H8 pin 67 P96/RXD", board_comment_for_instruction(analysis, 0x1014))

    def test_sci2_disabled_comments_say_it_is_not_traced_path(self):
        instructions = {
            0x2000: ins(0x2000, "MOV:G.B", "#H'80, @SYSCR2", [0xFEFD]),
            0x2004: ins(0x2004, "MOV:G.B", "#H'30, @SCI2_SCR", [0xFEF2]),
        }

        analysis = analyze_board_profile(instructions)

        syscr2_comment = board_comment_for_instruction(analysis, 0x2000)
        self.assertIn("P9SCI2E=0", syscr2_comment)
        self.assertIn("SCI2 is not the traced MAX202 path", syscr2_comment)

        sci2_comment = board_comment_for_instruction(analysis, 0x2004)
        self.assertIn("SCI2 SCR write; not the traced MAX202 path", sci2_comment)
        self.assertIn("P9SCI2E=0 disables SCI2 pins P92/P93/P94", sci2_comment)
        self.assertFalse(analysis["channels"]["SCI2"]["traced_to_max202"])
        self.assertFalse(analysis["channels"]["SCI2"]["p9sci2e"])


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