from __future__ import annotations

from functools import lru_cache

from ..constants import MODE_ADMIN, SKILL_SCOPE_BUSINESS
from .admin_content import AdminContentSkill
from .base import AiAssistantSkill
from .booking import BookingSkill
from .contact import ContactSkill
from .page_search import PageSearchSkill
from .product_detail import ProductDetailSkill
from .product_search import ProductSearchSkill
from .quote import QuoteSkill
from .seo_analysis import SeoAnalysisSkill
from .site_info import SiteInfoSkill

_EXTERNAL_SKILLS: dict[str, AiAssistantSkill] = {}


def _built_in_skills() -> list[AiAssistantSkill]:
    return [
        SiteInfoSkill(),
        PageSearchSkill(),
        ProductSearchSkill(),
        ProductDetailSkill(),
        QuoteSkill(),
        ContactSkill(),
        BookingSkill(),
        AdminContentSkill(),
        SeoAnalysisSkill(),
    ]


def register_skill(skill: AiAssistantSkill) -> None:
    if not isinstance(skill, AiAssistantSkill):
        raise TypeError("skill must be an AiAssistantSkill instance")
    if not getattr(skill, "key", ""):
        raise ValueError("skill.key is required")

    built_in_keys = {built_in.key for built_in in _built_in_skills()}
    if skill.key in built_in_keys:
        raise ValueError(f"skill key '{skill.key}' is reserved by a built-in skill")

    _EXTERNAL_SKILLS[skill.key] = skill
    get_default_skill_registry.cache_clear()


def get_registered_external_skills() -> list[AiAssistantSkill]:
    return list(_EXTERNAL_SKILLS.values())


def clear_registered_skills() -> None:
    _EXTERNAL_SKILLS.clear()
    get_default_skill_registry.cache_clear()


class SkillRegistry:
    def __init__(self, skills: list[AiAssistantSkill]):
        self._skills = {skill.key: skill for skill in skills}

    def all(self) -> list[AiAssistantSkill]:
        return list(self._skills.values())

    def get_enabled_skills(
        self, site, settings_obj, mode: str, capability_context=None
    ) -> list[AiAssistantSkill]:
        enabled: list[AiAssistantSkill] = []
        for skill in self.all():
            if skill.skill_scope == SKILL_SCOPE_BUSINESS:
                if (
                    capability_context is None
                    or not capability_context.business_skills_allowed
                ):
                    continue
            if not skill.is_enabled(site, settings_obj, mode):
                continue
            if mode != MODE_ADMIN and not skill.public_safe:
                continue
            enabled.append(skill)
        return enabled


@lru_cache(maxsize=1)
def get_default_skill_registry() -> SkillRegistry:
    return SkillRegistry(
        skills=[*_built_in_skills(), *get_registered_external_skills()]
    )
