"""APB (Advanced Peripheral Bus) protocol decoder."""

from __future__ import annotations
from dataclasses import dataclass

from ewal.protocol.base import Transaction


@dataclass
class APBTxn:
    addr: int
    data: int
    write: bool
    start: int
    end: int
    slverr: bool = False


class APB:
    """APB protocol decoder."""

    @staticmethod
    def bind(**signals) -> "BoundAPB":
        return BoundAPB(signals)


class BoundAPB:
    def __init__(self, signals: dict):
        self.signals = signals
        self._trace = None
        for sig in signals.values():
            if hasattr(sig, "_trace"):
                self._trace = sig._trace
                break

    def _val(self, name, index):
        sig = self.signals.get(name)
        if sig is None:
            return None
        old = self._trace._index
        self._trace._index = index
        self._trace._virtual_cache.clear()
        v = sig.value
        self._trace._index = old
        return v

    def transactions(self) -> list[APBTxn]:
        """Extract APB transactions (PSEL & PENABLE & PREADY)."""
        t = self._trace
        if t is None:
            return []

        psel = self.signals.get("psel")
        penable = self.signals.get("penable")
        pready = self.signals.get("pready")
        if not all([psel, penable, pready]):
            return []

        hs_indices = t.find(psel & penable & pready)
        results = []

        for idx in hs_indices:
            addr = self._val("paddr", idx) or 0
            pwrite = self._val("pwrite", idx)
            is_write = bool(pwrite)
            data = self._val("pwdata" if is_write else "prdata", idx) or 0
            slverr = bool(self._val("pslverr", idx) or 0)

            results.append(APBTxn(
                addr=addr, data=data, write=is_write,
                start=idx, end=idx, slverr=slverr,
            ))

        return results
