import typing

from iterable.base import BaseFileIterable

try:
    import dpkt

    HAS_DPKT = True
except ImportError:
    HAS_DPKT = False


class PCAPIterable(BaseFileIterable):
    """PCAP iterable"""

    datamode = "binary"

    def __init__(
        self,
        filename: str = None,
        stream: typing.IO = None,
        codec=None,
        binary: bool = True,
        encoding: str = None,
        noopen: bool = False,
        mode: str = "r",
        options: dict = None,
    ):
        if not HAS_DPKT:
            raise ImportError("dpkt is required for PCAP support. Install with 'pip install iterabledata[pcap]'")
        super().__init__(
            filename, stream, codec, binary=True, encoding=encoding, noopen=noopen, mode=mode, options=options
        )
        self.reader = None
        self._iter = None

    def read(self, skip_empty: bool = True):
        if self._iter is None:
            self._iter = iter(self)
        try:
            timestamp, buf = next(self._iter)
            return {"timestamp": timestamp, "data": buf}
        except StopIteration:
            return None

    def __iter__(self):
        if self.fobj is None:
            self.open()

        # Determine if it's pcap or pcapng based on magic bytes or just try pcap first
        # dpkt doesn't auto-detect easily from stream, but we can try.
        # However, for now, let's assume pcap.Reader. pcapng.Reader is also available.
        # A simple heuristic check could be useful, or we trust dpkt.

        try:
            self.reader = dpkt.pcap.Reader(self.fobj)
        except (ValueError, dpkt.dpkt.NeedData):
            # Fallback for pcapng or invalid
            try:
                self.fobj.seek(0)
                self.reader = dpkt.pcapng.Reader(self.fobj)
            except Exception:
                # If simple pcap failed, it might have been really pcap but empty/corrupt,
                # or it was pcapng and that failed too.
                # Raise the original error or a generic one.
                self.fobj.seek(0)
                self.reader = dpkt.pcap.Reader(self.fobj)

        yield from self.reader

    def write(self, record: dict):
        raise NotImplementedError("Writing PCAP files is not yet supported")

    def write_bulk(self, records: list[dict]):
        raise NotImplementedError("Writing PCAP files is not yet supported")
