from __future__ import annotations
import threading
from collections.abc import Hashable
from typing import (
    Callable,
    Generic,
    Optional,
    Sequence,
    TypeVar,
)
from dataclasses import dataclass

from instaui.launch_collector import get_launch_collector
from instaui.runtime import update_web_server_info
from instaui.systems import func_system
from . import _utils


ASYNC_URL = "/instaui/watch/async"
SYNC_URL = "/instaui/watch/sync"

update_web_server_info(watch_url=SYNC_URL, watch_async_url=ASYNC_URL)

_watch_handlers: dict[Hashable, _utils.HandlerInfo] = {}
dict_lock = threading.Lock()


def register_handler(
    key: str,
    handler: Callable,
    outputs_binding_count: int,
):
    if key in _watch_handlers:
        return
    with dict_lock:
        _watch_handlers[key] = _utils.HandlerInfo.from_handler(
            handler, outputs_binding_count
        )


def get_handler_info(key: str) -> _utils.HandlerInfo:
    return _watch_handlers.get(key)  # type: ignore


def get_statistics_info():
    return {
        "_watch_handlers count": len(_watch_handlers),
        "_watch_handlers keys": list(_watch_handlers.keys()),
    }


def create_handler_key(
    page_path: str,
    handler: Callable,
    extra_key: Optional[Sequence[Hashable]] = None,
):
    _, lineno, _ = func_system.get_function_location_info(handler)
    key = (
        f"path:{page_path}|line:{lineno}"
        if get_launch_collector().debug_mode
        else f"{page_path}|{lineno}"
    )
    if extra_key:
        key = repr(tuple(extra_key) + (key,))

    return key


_TWatchStateValue = TypeVar("_TWatchStateValue")


@dataclass(frozen=True)
class WatchState(Generic[_TWatchStateValue]):
    new_value: _TWatchStateValue
    old_value: _TWatchStateValue
    modified: bool
