from __future__ import annotations

from .model import EA
from .tables import IO_BITFIELDS, IO_DTE_BITS, IO_PRIORITY_FIELDS, IO_REGISTERS


def h8(value: int) -> str:
    return f"H'{value & 0xFF:02X}"


def h16(value: int) -> str:
    return f"H'{value & 0xFFFF:04X}"


def h24(value: int) -> str:
    return f"H'{value & 0xFFFFFF:06X}"


def s8(value: int) -> int:
    value &= 0xFF
    return value - 0x100 if value & 0x80 else value


def s16(value: int) -> int:
    value &= 0xFFFF
    return value - 0x10000 if value & 0x8000 else value


def parse_int(text: str) -> int:
    return int(text.replace("H'", "0x").replace("$", "0x"), 0)


def reg_list(mask: int) -> str:
    regs = [f"R{idx}" for idx in range(8) if mask & (1 << idx)]
    return "{" + ",".join(regs) + "}" if regs else "{}"


def disp_text(value: int) -> str:
    if value < 0:
        return f"-{h16(-value) if value < -0xFF else h8(-value)}"
    return h16(value) if value > 0xFF else h8(value)


def short_abs(low: int) -> str:
    return f"@BR:{h8(low)}"


def control_reg(ccc: int, size: str) -> str:
    if size == "W":
        return "SR" if ccc == 0 else f"CR{ccc}?"
    return {
        0: "CCR",
        1: "BR",
        2: "EP",
        3: "DP",
        4: "TP",
    }.get(ccc, f"CR{ccc}?")


def label_for(address: int) -> str:
    return f"loc_{address:04X}"


def label_or_h(address: int, labels: dict[int, str]) -> str:
    return labels.get(address, label_for(address))


def _bitfield_name(address: int, bit: int) -> str | None:
    priority_name = _priority_bit_name(address, bit)
    if priority_name:
        return priority_name
    dte_name = _dte_bit_name(address, bit)
    if dte_name:
        return dte_name
    return IO_BITFIELDS.get(address, {}).get(bit)


def _bitfield_values(address: int, value: int) -> str:
    fields = IO_BITFIELDS.get(address)
    if not fields:
        return ""
    parts = [f"{name}={(value >> bit) & 1}" for bit, name in sorted(fields.items(), reverse=True)]
    return " ".join(parts)


def _adcsr_semantics(value: int) -> str:
    channels_single = ["AN0", "AN1", "AN2", "AN3", "AN4", "AN5", "AN6", "AN7"]
    channels_scan = ["AN0", "AN0-AN1", "AN0-AN2", "AN0-AN3", "AN4", "AN4-AN5", "AN4-AN6", "AN4-AN7"]
    scan = bool(value & 0x10)
    channels = channels_scan[value & 0x07] if scan else channels_single[value & 0x07]
    mode = "scan" if scan else "single"
    state = "start" if value & 0x20 else "halt"
    interrupt = "ADI enabled" if value & 0x40 else "ADI disabled"
    conversion = "138-state max" if value & 0x08 else "274-state max"
    return f"A/D {state}, {mode} {channels}, {conversion}, {interrupt}"


def _priority_bit_name(address: int, bit: int) -> str | None:
    for shift, source in IO_PRIORITY_FIELDS.get(address, ()):
        if shift <= bit <= shift + 2:
            return f"{source} priority bit {bit - shift}"
    if address in IO_PRIORITY_FIELDS and bit in (7, 3):
        return "reserved priority bit"
    return None


def _dte_bit_name(address: int, bit: int) -> str | None:
    fields = IO_DTE_BITS.get(address)
    if fields is None:
        return None
    source = fields.get(bit)
    return f"{source} DTC enable" if source else "reserved DTE bit"


def _ipr_semantics(address: int, value: int) -> str:
    parts: list[str] = []
    for shift, source in IO_PRIORITY_FIELDS[address]:
        priority = (value >> shift) & 0x07
        parts.append(f"{source} priority={priority}")
    reserved = _set_bit_numbers(value, 0x88)
    if reserved:
        parts.append(f"reserved bits {reserved} should be 0")
    return "; ".join(parts)


def _dte_semantics(address: int, value: int) -> str:
    fields = IO_DTE_BITS[address]
    parts = [
        f"{source} {'DTC enabled' if value & (1 << bit) else 'CPU interrupt'}"
        for bit, source in sorted(fields.items(), reverse=True)
    ]
    assigned_mask = 0
    for bit in fields:
        assigned_mask |= 1 << bit
    reserved = _set_bit_numbers(value, (~assigned_mask) & 0xFF)
    if reserved:
        parts.append(f"reserved bits {reserved} should be 0")
    return "; ".join(parts)


def _set_bit_numbers(value: int, mask: int) -> str:
    bits = [str(bit) for bit in range(7, -1, -1) if value & mask & (1 << bit)]
    return ", ".join(bits)


def _sci_smr_semantics(value: int) -> str:
    mode = "sync" if value & 0x80 else "async"
    char_len = "7-bit" if value & 0x40 else "8-bit"
    parity = "odd parity" if value & 0x10 else "even parity"
    parity = parity if value & 0x20 else "no parity"
    stop = "2 stop" if value & 0x08 else "1 stop"
    clock = ["phi", "phi/4", "phi/16", "phi/64"][value & 0x03]
    return f"SCI {mode}, {char_len}, {parity}, {stop}, clock {clock}"


def _sci_scr_semantics(value: int) -> str:
    enabled: list[str] = []
    if value & 0x20:
        enabled.append("TX")
    if value & 0x10:
        enabled.append("RX")
    if value & 0x80:
        enabled.append("TXI")
    if value & 0x40:
        enabled.append("RXI/ERI")
    clock = "external clock" if value & 0x02 else "internal clock"
    if value & 0x01:
        clock += ", SCK output"
    return f"SCI enables {','.join(enabled) if enabled else 'none'}, {clock}"


def _wcr_semantics(value: int) -> str:
    modes = ["programmable wait", "no wait states", "pin wait", "pin auto-wait"]
    counts = ["0 waits", "1 wait", "2 waits", "3 waits"]
    return f"{modes[(value >> 2) & 0x03]}, {counts[value & 0x03]}"


def _wdt_semantics(value: int) -> str:
    if value <= 0xFF:
        data = value
        return _wdt_tcsr_data_semantics(data)
    password = (value >> 8) & 0xFF
    data = value & 0xFF
    if password == 0xA5:
        return f"TCSR password H'A5, {_wdt_tcsr_data_semantics(data)}"
    if password == 0x5A:
        return f"TCNT password H'5A, counter write {h8(data)}"
    return f"watchdog password {h8(password)}, data {h8(data)}"


def _wdt_tcsr_data_semantics(value: int) -> str:
    clock = ["phi/2", "phi/32", "phi/64", "phi/128", "phi/256", "phi/512", "phi/2048", "phi/4096"][value & 0x07]
    mode = "watchdog NMI" if value & 0x40 else "interval IRQ0"
    state = "enabled" if value & 0x20 else "disabled"
    return f"WDT {state}, {mode}, clock {clock}"


def _rstcsr_semantics(value: int) -> str:
    if value <= 0xFF:
        data = value
        password = None
    else:
        password = (value >> 8) & 0xFF
        data = value & 0xFF
    if password == 0xA5:
        return f"RSTCSR password H'A5, clear WRST with data {h8(data)}"
    if password == 0x5A:
        rstoe = "RES output enabled" if data & 0x40 else "RES output disabled"
        return f"RSTCSR password H'5A, {rstoe}"
    return "RSTCSR status/control"


def _semantic_values(address: int, value: int) -> str:
    if address in IO_PRIORITY_FIELDS:
        return _ipr_semantics(address, value)
    if address in IO_DTE_BITS:
        return _dte_semantics(address, value)
    if address == 0xFEE8:
        return _adcsr_semantics(value)
    if address in (0xFED8, 0xFEF0):
        return _sci_smr_semantics(value)
    if address in (0xFEDA, 0xFEF2):
        return _sci_scr_semantics(value)
    if address == 0xFEFC:
        brle = "bus release pins enabled" if value & 0x08 else "P12/P13 are I/O"
        irq0 = "IRQ0 enabled" if value & 0x20 else "IRQ0 disabled"
        irq1 = "IRQ1 enabled" if value & 0x40 else "IRQ1 disabled"
        return f"{brle}, {irq0}, {irq1}"
    if address == 0xFEFD:
        enabled = [name for bit, name in ((0, "SCI2 pins"), (1, "P9 PWM"), (2, "P6 PWM"), (3, "IRQ2"), (4, "IRQ3"), (5, "IRQ4"), (6, "IRQ5")) if value & (1 << bit)]
        return "enabled " + ", ".join(enabled) if enabled else "alternate pin functions disabled"
    if address == 0xFEEC:
        return _wdt_semantics(value)
    if address == 0xFF10:
        return _wcr_semantics(value)
    if address == 0xFF11:
        return "on-chip RAM enabled" if value & 0x80 else "on-chip RAM disabled"
    if address == 0xFF12:
        return f"mode select bits MDS={value & 0x07}"
    if address == 0xFF14:
        return _rstcsr_semantics(value)
    return ""


def write_comment(ea: EA, value: int | None) -> str:
    if ea.address is None or ea.address not in IO_REGISTERS:
        return ""
    name = IO_REGISTERS[ea.address]
    if value is None:
        return name
    text = f"{name} = {h16(value) if value > 0xFF else h8(value)}"
    fields = _bitfield_values(ea.address, value)
    semantic = _semantic_values(ea.address, value)
    details = "; ".join(part for part in (fields, semantic) if part)
    return f"{text} ({details})" if details else text


def bit_comment(mnemonic: str, ea: EA, bit: int) -> str:
    if ea.address is None or ea.address not in IO_REGISTERS:
        return ""
    action = {"BSET": "set", "BCLR": "clear", "BNOT": "toggle", "BTST": "test"}.get(
        mnemonic.split(".")[0],
        "bit",
    )
    bit_name = _bitfield_name(ea.address, bit)
    if bit_name:
        return f"{action} {bit_name} (bit {bit}) of {IO_REGISTERS[ea.address]}"
    return f"{action} bit {bit} of {IO_REGISTERS[ea.address]}"
