from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any, Callable, Dict, Optional, TypeVar

from core.logging import get_logger


class BaseServiceProvider(ABC):
    def __init__(self, service_name: str) -> None:
        self.service_name = service_name
        self._initialized = False
        self.logger = get_logger("services.base").bind(service=service_name)

    @abstractmethod
    async def initialize(self, **kwargs: Any) -> bool:
        raise NotImplementedError

    @abstractmethod
    async def close(self) -> bool:
        raise NotImplementedError

    @abstractmethod
    async def health_check(self) -> Dict[str, Any]:
        raise NotImplementedError

    @property
    def is_initialized(self) -> bool:
        return self._initialized

    def _set_initialized(self, value: bool) -> None:
        self._initialized = value

    def get_service_info(self) -> Dict[str, Any]:
        return {
            "name": self.service_name,
            "initialized": self._initialized,
            "type": self.__class__.__name__,
        }


class ServiceRegistry:
    _services: Dict[str, Callable[..., BaseServiceProvider]] = {}

    @classmethod
    def register(
        cls, service_name: str, factory: Callable[..., BaseServiceProvider]
    ) -> None:
        cls._services = {**cls._services, service_name: factory}

    @classmethod
    def get_service_factory(
        cls, service_name: str
    ) -> Optional[Callable[..., BaseServiceProvider]]:
        return cls._services.get(service_name)

    @classmethod
    def list_services(cls) -> list[str]:
        return sorted(cls._services.keys())

    @classmethod
    def create_service(
        cls, service_name: str, **kwargs: Any
    ) -> Optional[BaseServiceProvider]:
        factory = cls.get_service_factory(service_name)
        if not factory:
            return None
        return factory(**kwargs)


def register_service(service_name: str) -> Callable[[type], type]:
    def decorator(service_class: type) -> type:
        ServiceRegistry.register(service_name, service_class)
        return service_class

    return decorator


TService = TypeVar("TService", bound=BaseServiceProvider)


def register_service_instance(service_name: str, service: TService) -> TService:
    ServiceRegistry.register(service_name, lambda: service)
    return service
