"""HandlerRegistry + HandlerExecutor — breach response handling."""

from __future__ import annotations

import logging
import threading
from typing import Any, Callable

from pyfortis._types import BreachAction, BreachRecord
from pyfortis.errors import HandlerNotFoundError

logger = logging.getLogger(__name__)

HandlerFn = Callable[[BreachRecord, dict[str, Any]], None]


class HandlerRegistry:
    """Thread-safe registry for breach action handlers."""

    def __init__(self) -> None:
        self._handlers: dict[str, HandlerFn] = {}
        self._lock = threading.Lock()

    def register(self, name: str, fn: HandlerFn) -> None:
        with self._lock:
            self._handlers[name] = fn

    def get(self, name: str) -> HandlerFn | None:
        with self._lock:
            return self._handlers.get(name)

    def has(self, name: str) -> bool:
        with self._lock:
            return name in self._handlers

    def names(self) -> list[str]:
        with self._lock:
            return list(self._handlers.keys())

    def decorator(self, name: str) -> Callable[[HandlerFn], HandlerFn]:
        def wrapper(fn: HandlerFn) -> HandlerFn:
            self.register(name, fn)
            return fn
        return wrapper


class HandlerExecutor:
    """Executes breach handlers from a HandlerRegistry."""

    def __init__(self, registry: HandlerRegistry) -> None:
        self._registry = registry

    def execute(
        self,
        breach: BreachRecord,
        context: dict[str, Any] | None = None,
    ) -> None:
        """Execute all handlers for a breach's actions."""
        ctx = context or {}
        for action in breach.actions:
            fn = self._registry.get(action.value)
            if fn is None:
                logger.warning(
                    "No handler for action '%s' on breach '%s'",
                    action.value,
                    breach.limit_name,
                )
                continue
            try:
                fn(breach, ctx)
            except Exception:
                logger.exception(
                    "Handler '%s' failed for breach '%s'",
                    action.value,
                    breach.limit_name,
                )

    def execute_all(
        self,
        breaches: list[BreachRecord],
        context: dict[str, Any] | None = None,
    ) -> None:
        """Execute handlers for all breaches."""
        for breach in breaches:
            self.execute(breach, context)


def _builtin_log_handler(breach: BreachRecord, context: dict[str, Any]) -> None:
    """Built-in log handler."""
    logger.warning(
        "[%s] %s: %s",
        breach.severity.value,
        breach.limit_name,
        breach.message,
    )


BUILTIN_HANDLERS: dict[str, HandlerFn] = {
    "log": _builtin_log_handler,
}
