import unittest

from h8536.cycles import estimate_cycles
from h8536.decoder import H8536Decoder
from h8536.rom import Rom


def decode_at(data: list[int], address: int = 0):
    return H8536Decoder(Rom(bytes(data), base=address)).decode(address)


class ManualCycleExamplesTest(unittest.TestCase):
    def test_add_word_register_indirect_matches_manual_even_and_odd_examples(self):
        even = decode_at([0xD8, 0x21], 0x0100)
        odd = decode_at([0xD8, 0x21], 0x0101)

        self.assertEqual(even.text, "ADD:G.W @R0, R1")
        self.assertEqual(estimate_cycles(even, "min")["cycles"], 6)
        self.assertEqual(estimate_cycles(even, "min")["base_cycles"], 5)
        self.assertEqual(estimate_cycles(even, "min")["alignment_adjustment"], 1)

        self.assertEqual(odd.text, "ADD:G.W @R0, R1")
        self.assertEqual(estimate_cycles(odd, "min")["cycles"], 5)
        self.assertEqual(estimate_cycles(odd, "min")["base_cycles"], 5)

    def test_jsr_register_indirect_matches_manual_stack_adjusted_example(self):
        even = decode_at([0x11, 0xD8], 0xFC00)
        odd = decode_at([0x11, 0xD8], 0xFC01)

        self.assertEqual(even.text, "JSR @R0")
        self.assertEqual(estimate_cycles(even, "min")["cycles"], 13)
        self.assertEqual(estimate_cycles(even, "min")["base_cycles"], 9)
        self.assertEqual(estimate_cycles(even, "min")["stack_adjustment"], 4)

        self.assertEqual(odd.text, "JSR @R0")
        self.assertEqual(estimate_cycles(odd, "min")["cycles"], 14)
        self.assertEqual(estimate_cycles(odd, "min")["alignment_adjustment"], 1)

    def test_conditional_branch_keeps_taken_and_not_taken_counts(self):
        instruction = decode_at([0x26, 0x02], 0x0000)
        cycles = estimate_cycles(instruction, "min")

        self.assertEqual(cycles["not_taken"], 3)
        self.assertEqual(cycles["taken"], 7)


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