"""Skill registry for managing marketing skills."""

from __future__ import annotations

import json
import re
from typing import Optional

from thefuzz import process

from ..types import ConversationContext, Skill, SkillMetadata
from ..utils.config import SKILLS_DIR
from ..utils.logger import Logger


class SkillRegistry:
    """Registry for managing and discovering skills."""

    def __init__(self) -> None:
        self.skills: dict[str, Skill] = {}
        self.manifest: Optional[dict] = None

    def initialize(self) -> None:
        """Initialize the skill registry."""
        Logger.info("Initializing skill registry")
        self._load_all_skills()

    def _load_all_skills(self) -> None:
        """Load all skills from manifest."""
        try:
            # Load manifest
            manifest_path = SKILLS_DIR / "skill.json"
            with open(manifest_path, "r") as f:
                self.manifest = json.load(f)

            # Load all skills from manifest
            skills_dict = self.manifest.get("skills", {})
            for category, skills_list in skills_dict.items():
                for skill_data in skills_list:
                    # Handle file path - may be relative to skills dir
                    file_path = skill_data.get("file", "")
                    if file_path.startswith("skills/"):
                        file_path = file_path[7:]  # Remove 'skills/' prefix
                    skill_path = SKILLS_DIR / file_path

                    content = ""
                    try:
                        with open(skill_path, "r") as f:
                            content = f.read()
                    except FileNotFoundError:
                        Logger.warn(f"Could not read skill file: {skill_path}")

                    metadata = SkillMetadata(
                        name=skill_data["name"],
                        description=skill_data["description"],
                        file=skill_data["file"],
                        url=skill_data.get("url", ""),
                        version=skill_data.get("version"),
                        endpoint=skill_data.get("endpoint"),
                    )

                    skill = Skill(
                        id=skill_data["name"],
                        name=skill_data["name"],
                        description=skill_data["description"],
                        category=category,
                        keywords=self._extract_keywords(
                            skill_data["name"], skill_data["description"], content
                        ),
                        file_path=str(skill_path),
                        metadata=metadata,
                        capabilities=self.manifest.get("capabilities", []),
                    )

                    self.skills[skill.id] = skill

            Logger.info(f"Loaded {len(self.skills)} skills")

        except Exception as e:
            Logger.error("Failed to load skills", e)
            raise Exception("Failed to initialize skill registry")

    def _extract_keywords(self, name: str, description: str, content: str) -> list[str]:
        """Extract keywords from skill data."""
        keywords = set()

        # Add name parts
        for part in re.split(r"[-_\s]", name):
            keywords.add(part.lower())

        # Add description words
        for word in description.lower().split():
            if len(word) > 3:
                keywords.add(word)

        # Marketing terms
        marketing_terms = [
            "blog",
            "content",
            "copy",
            "seo",
            "cro",
            "social",
            "email",
            "marketing",
            "brand",
            "strategy",
            "analytics",
            "twitter",
            "web",
            "scrape",
            "extract",
            "crawl",
            "remix",
            "draft",
        ]

        content_lower = content.lower()
        for term in marketing_terms:
            if term in content_lower:
                keywords.add(term)

        return list(keywords)

    def detect_skill(self, user_input: str, context: ConversationContext) -> Optional[Skill]:
        """Detect the best skill for user input."""
        lower_input = user_input.lower()

        # 1. Direct skill mention
        for skill_id, skill in self.skills.items():
            normalized_id = skill_id.lower().replace("-", " ").replace("_", " ")
            if normalized_id in lower_input or skill_id.lower() in lower_input:
                Logger.info(f"Direct skill match: {skill_id}")
                return skill

        # 2. Fuzzy search
        if self.skills:
            skill_names = [s.name for s in self.skills.values()]
            matches = process.extract(user_input, skill_names, limit=3)
            if matches and matches[0][1] > 60:  # threshold
                for skill in self.skills.values():
                    if skill.name == matches[0][0]:
                        Logger.info(f"Fuzzy skill match: {skill.name}")
                        return skill

        # 3. Intent-based detection
        intent_map = {
            "copywriting": ["write", "copy", "landing", "website", "page"],
            "seo-audit": ["seo", "audit", "optimize", "ranking", "search"],
            "social-content": ["social", "twitter", "linkedin", "post", "tweet"],
            "email-sequence": ["email", "sequence", "campaign", "newsletter"],
            "web-scrape": ["scrape", "extract", "crawl", "website", "url"],
            "twitter-remix": ["remix", "twitter", "tweet", "viral"],
            "brand_consistency_check": ["brand", "check", "validate", "consistency"],
            "content_refine": ["refine", "improve", "edit", "rewrite"],
            "blog-generate-with-images": ["blog", "article", "images", "pictures"],
        }

        for skill_id, keywords in intent_map.items():
            match_count = sum(1 for k in keywords if k in lower_input)
            if match_count >= 2:
                skill = self.skills.get(skill_id)
                if skill:
                    Logger.info(f"Intent-based skill match: {skill_id}")
                    return skill

        # 4. Context-based: continue with current skill
        if context.current_skill:
            current = self.skills.get(context.current_skill)
            if current:
                Logger.info(f"Continuing with current skill: {current.id}")
                return current

        return None

    def load_skill_content(self, skill_id: str) -> str:
        """Load content of a skill."""
        skill = self.skills.get(skill_id)
        if not skill:
            raise ValueError(f"Skill not found: {skill_id}")

        try:
            with open(skill.file_path, "r") as f:
                return f.read()
        except FileNotFoundError:
            return skill.description

    def get_all_skills(self) -> list[Skill]:
        """Get all skills."""
        return list(self.skills.values())

    def get_skills_by_category(self, category: str) -> list[Skill]:
        """Get skills by category."""
        return [s for s in self.skills.values() if s.category == category]

    def search_skills(self, query: str) -> list[Skill]:
        """Search skills by query."""
        if not self.skills:
            return []

        results = []
        skill_names = [s.name for s in self.skills.values()]
        matches = process.extract(query, skill_names, limit=10)

        for match, score in matches:
            if score > 40:
                for skill in self.skills.values():
                    if skill.name == match:
                        results.append(skill)
                        break

        return results

    def get_skill(self, skill_id: str) -> Optional[Skill]:
        """Get a skill by ID."""
        return self.skills.get(skill_id)
