"""Plugin system for custom trace formats.

Register custom format readers that integrate with ewal.load().

Usage:
    @ewal.register_format(".my_fmt")
    class MyReader(ewal.TraceReader):
        def __init__(self, path): ...
        def signal_names(self) -> list[str]: ...
        def max_index(self) -> int: ...
        def signal_value(self, name, index) -> int: ...
        def signal_width(self, name) -> int: ...
"""

from __future__ import annotations
from typing import Any, Optional, TYPE_CHECKING

# Registry of custom format readers
_format_registry: dict[str, type] = {}


class TraceReader:
    """Base class for custom trace format readers.

    Subclass and implement the required methods to support a new
    trace file format.
    """

    def signal_names(self) -> list[str]:
        raise NotImplementedError

    def scopes(self) -> list[str]:
        return []

    def max_index(self) -> int:
        raise NotImplementedError

    def timestamp(self, index: int) -> int:
        return index

    def signal_value(self, name: str, index: int) -> Any:
        raise NotImplementedError

    def signal_value_raw(self, name: str, index: int) -> int:
        val = self.signal_value(name, index)
        return int(val) if val is not None else 0

    def signal_width(self, name: str) -> int:
        return 1

    def signal_id(self, name: str) -> Optional[int]:
        try:
            return self.signal_names().index(name)
        except ValueError:
            return None

    def signal_values_range(self, name: str, start: int, end: int) -> list:
        return [self.signal_value(name, i) for i in range(start, end)]

    def resolve(self, scope: str, short_name: str) -> Optional[str]:
        candidate = f"{scope}.{short_name}" if scope else short_name
        if candidate in self.signal_names():
            return candidate
        return None

    def local_signals(self, scope: str) -> list[str]:
        prefix = f"{scope}." if scope else ""
        return [s for s in self.signal_names()
                if s.startswith(prefix) and "." not in s[len(prefix):]]

    def local_scopes(self, scope: str) -> list[str]:
        prefix = f"{scope}." if scope else ""
        result = set()
        for s in self.scopes():
            if s.startswith(prefix):
                rest = s[len(prefix):]
                child = rest.split(".")[0]
                if child:
                    result.add(f"{scope}.{child}" if scope else child)
        return list(result)

    def find(self, expr) -> list[int]:
        return []

    def eval_expr(self, expr, index: int) -> Any:
        return None

    def eval_expr_bool(self, expr, index: int) -> bool:
        return False


def register_format(extension: str):
    """Decorator to register a custom trace format reader.

    Usage:
        @ewal.register_format(".my_fmt")
        class MyReader(ewal.TraceReader):
            def __init__(self, path): ...
            ...

        # Now works:
        t = ewal.load("trace.my_fmt")
    """
    def decorator(cls):
        ext = extension.lower()
        if not ext.startswith("."):
            ext = "." + ext
        _format_registry[ext] = cls
        return cls
    return decorator


def get_reader_for_extension(extension: str) -> Optional[type]:
    """Look up a registered reader for a file extension."""
    ext = extension.lower()
    if not ext.startswith("."):
        ext = "." + ext
    return _format_registry.get(ext)
