"""Handler registry and user-callback invocation (threaded)."""
from __future__ import annotations

import threading
import traceback
from typing import Any, Callable

from TgrEzLi.models import clear_context, set_context
from TgrEzLi.types import TgArgsData, TgCbData, TgCmdData, TgMsgData


def call_user_function(
    logger: Any,
    func: Callable[[], None],
    *,
    TgMsg: TgMsgData | None = None,
    TgCmd: TgCmdData | None = None,
    TgCb: TgCbData | None = None,
    TgArgs: TgArgsData | None = None,
) -> None:
    """Run the user handler in a background thread with thread-local context set."""
    def worker() -> None:
        try:
            set_context(TgMsg=TgMsg, TgCmd=TgCmd, TgCb=TgCb, TgArgs=TgArgs)
            func()
        except Exception as e:  # noqa: BLE001
            logger.error("Error in user handler: %s", e)
            logger.debug(traceback.format_exc())
        finally:
            clear_context()

    thread = threading.Thread(target=worker, daemon=True)
    thread.start()


class HandlerRegistry:
    """Registry for message, command, callback, and API route handlers."""

    __slots__ = ("message_handlers", "command_handlers", "callback_handlers", "api_routes")

    def __init__(self) -> None:
        self.message_handlers: list[tuple[set[str], Callable[[], None]]] = []
        self.command_handlers: dict[str, list[tuple[set[str], Callable[[], None]]]] = {}
        self.callback_handlers: list[tuple[set[str], Callable[[], None]]] = []
        self.api_routes: dict[str, dict[str, Any]] = {}  # path -> {"args": [...], "func": ...}

    def register_message_handler(self, func: Callable[[], None], chats: set[str]) -> None:
        name = getattr(func, "__name__", None)
        if name is not None:
            self.message_handlers[:] = [(c, f) for c, f in self.message_handlers if getattr(f, "__name__", None) != name]
        self.message_handlers.append((chats, func))

    def register_command_handler(self, command: str, func: Callable[[], None], chats: set[str]) -> None:
        name = getattr(func, "__name__", None)
        lst = self.command_handlers.setdefault(command, [])
        if name is not None:
            lst[:] = [(c, f) for c, f in lst if getattr(f, "__name__", None) != name]
        lst.append((chats, func))

    def register_callback_handler(self, func: Callable[[], None], chats: set[str]) -> None:
        name = getattr(func, "__name__", None)
        if name is not None:
            self.callback_handlers[:] = [(c, f) for c, f in self.callback_handlers if getattr(f, "__name__", None) != name]
        self.callback_handlers.append((chats, func))

    def register_api_route(self, endpoint: str, args_list: list[str], func: Callable[[], None]) -> None:
        self.api_routes[endpoint] = {"args": args_list, "func": func}


__all__ = ["call_user_function", "HandlerRegistry"]
