"""AXI4-Stream protocol decoder."""

from __future__ import annotations
from dataclasses import dataclass
from typing import Any

from ewal.protocol.base import Transaction


@dataclass
class AXI4StreamTxn:
    data: list[int]
    start: int
    end: int
    tlast_at: int = -1


class AXI4Stream:
    """AXI4-Stream protocol decoder."""

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


class BoundAXI4Stream:
    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[AXI4StreamTxn]:
        """Extract stream transactions (delimited by TLAST)."""
        t = self._trace
        if t is None:
            return []

        tvalid = self.signals.get("tvalid")
        tready = self.signals.get("tready")
        if tvalid is None or tready is None:
            return []

        hs_indices = t.find(tvalid & tready)
        results = []
        current_data = []
        start = None

        for idx in hs_indices:
            if start is None:
                start = idx
            current_data.append(self._val("tdata", idx) or 0)
            tlast = self._val("tlast", idx)
            if tlast:
                results.append(AXI4StreamTxn(
                    data=current_data, start=start, end=idx, tlast_at=idx,
                ))
                current_data = []
                start = None

        # Remaining data without TLAST
        if current_data and start is not None:
            results.append(AXI4StreamTxn(
                data=current_data, start=start, end=hs_indices[-1],
            ))

        return results
