"""Skill command handler.

Handles /skill command - load or unload agent skills.
"""

import logging
from typing import Dict, Any, Optional

from kollabor_events.models import (
    CommandResult,
    SlashCommand,
    UIConfig,
    CommandDefinition,
    CommandCategory,
    CommandMode,
    SubcommandInfo,
)
from ..base import BaseCommandHandler

logger = logging.getLogger(__name__)


class SkillCommandHandler(BaseCommandHandler):
    """Handles /skill command - load or unload agent skills."""

    MODAL_ACTIONS = {
        "load_skill",
        "unload_skill",
        "create_skill_prompt",
        "create_skill_submit",
        "edit_skill_prompt",
        "edit_skill_submit",
        "delete_skill_prompt",
        "delete_skill_confirm",
        "toggle_default_skill",
        "toggle_global_default_skill",
    }

    def __init__(
        self,
        command_registry,
        event_bus,
        agent_manager,
        llm_service=None,
    ):
        """Initialize skill command handler.

        Args:
            command_registry: Command registry for registration.
            event_bus: Event bus for service lookup.
            agent_manager: Agent manager instance.
            llm_service: Optional LLM service (for dynamic lookup).
        """
        super().__init__(command_registry, event_bus)
        self.agent_manager = agent_manager
        self._llm_service_override = llm_service

    @property
    def llm_service(self):
        """Get LLM service dynamically via event bus."""
        if self._llm_service_override is not None:
            return self._llm_service_override
        if self.event_bus and hasattr(self.event_bus, "get_service"):
            return self.event_bus.get_service("llm_service")
        return None

    def register_commands(self) -> None:
        """Register /skill command."""
        skill_command = CommandDefinition(
            name="skill",
            description="Load or unload agent skills",
            handler=self.handle_skill,
            plugin_name="system",
            category=CommandCategory.AGENT,
            mode=CommandMode.STATUS_TAKEOVER,
            aliases=["sk"],
            icon="[SKILL]",
            subcommands=[
                SubcommandInfo("list", "", "Show skill selection modal"),
                SubcommandInfo("load", "<name>", "Load specified skill"),
                SubcommandInfo("unload", "<name>", "Unload specified skill"),
                SubcommandInfo("create", "", "Open create skill form"),
            ],
            ui_config=UIConfig(
                type="modal",
                navigation=["? ?", "Enter", "Esc"],
                height=15,
                title="Agent Skills",
                footer="↑↓ navigate • Enter select • Esc exit",
            ),
        )
        self.command_registry.register_command(skill_command)

    async def handle_skill(self, command: SlashCommand) -> CommandResult:
        """Handle /skill command.

        Args:
            command: Parsed slash command.

        Returns:
            Command execution result.
        """
        try:
            if not self.agent_manager:
                return CommandResult(
                    success=False,
                    message="Agent manager not available",
                    display_type="error",
                )

            active_agent = self.agent_manager.get_active_agent()
            if not active_agent:
                return CommandResult(
                    success=False,
                    message="No active agent. Use /agent <name> first.",
                    display_type="error",
                )

            args = command.args or []

            if not args:
                # Show skill selection modal
                return await self._show_skills_modal()
            elif args[0] in ("list", "ls"):
                # Show skill selection modal
                return await self._show_skills_modal()
            elif args[0] == "create":
                # Show create skill form modal
                return await self._show_create_skill_modal()
            elif args[0] == "load" and len(args) > 1:
                # Load skill
                skill_name = args[1]
                return await self._load_skill(skill_name)
            elif args[0] == "unload" and len(args) > 1:
                # Unload skill
                skill_name = args[1]
                return await self._unload_skill(skill_name)
            else:
                # Try to load skill by name directly
                skill_name = args[0]
                return await self._load_skill(skill_name)

        except Exception as e:
            self.logger.error(f"Error in skill command: {e}")
            return CommandResult(
                success=False,
                message=f"Error managing skills: {str(e)}",
                display_type="error",
            )

    def _get_skills_modal_definition(
        self, skip_reload: bool = False
    ) -> Optional[Dict[str, Any]]:
        """Get modal definition for skill selection.

        Args:
            skip_reload: If True, don't reload from disk (use current state).

        Returns:
            Modal definition dictionary, or None if no skills available.
        """
        active_agent = self.agent_manager.get_active_agent()
        if not active_agent:
            return None

        # Refresh agent from disk to pick up any changes (unless skipped)
        if not skip_reload:
            self.agent_manager.refresh()
            # Re-get active agent in case it was refreshed
            active_agent = self.agent_manager.get_active_agent()
            if not active_agent:
                return None

        skills = active_agent.list_skills()
        active_skills = active_agent.active_skills

        # Check project and global defaults
        import json

        local_config = (
            self.agent_manager.local_agents_dir / active_agent.name / "agent.json"
            if self.agent_manager.local_agents_dir
            else None
        )
        global_config = (
            self.agent_manager.global_agents_dir / active_agent.name / "agent.json"
        )

        project_defaults = set()
        global_defaults = set()

        if local_config and local_config.exists():
            try:
                config_data = json.loads(local_config.read_text(encoding="utf-8"))
                project_defaults = set(config_data.get("default_skills", []))
            except Exception as e:
                logger.debug(f"Failed to load local skill config: {e}")

        if global_config.exists():
            try:
                config_data = json.loads(global_config.read_text(encoding="utf-8"))
                global_defaults = set(config_data.get("default_skills", []))
            except Exception as e:
                logger.debug(f"Failed to load global skill config: {e}")

        if not skills:
            return None

        # Build skill list for modal
        skill_items = []
        for skill in skills:
            is_loaded = skill.name in active_skills
            is_proj_default = skill.name in project_defaults
            is_global_default = skill.name in global_defaults

            action = "unload_skill" if is_loaded else "load_skill"
            description = skill.description or f"Skill file: {skill.file_path.name}"

            # Build status indicators for description
            status_parts = []
            if is_proj_default:
                status_parts.append("proj")
            if is_global_default:
                status_parts.append("global")
            if status_parts:
                description = f"[{'+'.join(status_parts)}] {description}"

            skill_items.append(
                {
                    "name": skill.name,
                    "description": description,
                    "skill_name": skill.name,
                    "action": action,
                    "loaded": is_loaded,
                    "is_default": is_proj_default or is_global_default,
                }
            )

        loaded_count = len(active_skills)
        total_count = len(skills)
        default_count = len(project_defaults | global_defaults)

        # Management options
        management_items = [
            {
                "name": "Create New Skill",
                "description": "Create a new skill file for this agent",
                "action": "create_skill_prompt",
            }
        ]

        return {
            "title": f"Skills - {active_agent.name}",
            "footer": "↑↓ navigate | Enter toggle | d/g default | e edit | r delete",
            # Width and height are dynamic (terminal_width - 2, terminal_height - 4)
            "sections": [
                {
                    "title": f"Available Skills ({loaded_count}/{total_count} loaded, {default_count} default)",
                    "commands": skill_items,
                },
                {"title": "Management", "commands": management_items},
            ],
            "actions": [
                {"key": "Enter", "label": "Toggle", "action": "toggle"},
                {
                    "key": "d",
                    "label": "Project Default",
                    "action": "toggle_default_skill",
                },
                {
                    "key": "g",
                    "label": "Global Default",
                    "action": "toggle_global_default_skill",
                },
                {"key": "e", "label": "Edit", "action": "edit_skill_prompt"},
                {"key": "r", "label": "Delete", "action": "delete_skill_prompt"},
                {"key": "Escape", "label": "Close", "action": "cancel"},
            ],
        }

    async def _show_skills_modal(self) -> CommandResult:
        """Show skill selection modal for active agent.

        Returns:
            Command result with modal UI.
        """
        active_agent = self.agent_manager.get_active_agent()
        if not active_agent:
            return CommandResult(
                success=False, message="No active agent", display_type="error"
            )

        modal_definition = self._get_skills_modal_definition()
        if not modal_definition:
            return CommandResult(
                success=True,
                message=f"Agent '{active_agent.name}' has no skills defined.\nAdd .md files to the agent directory to create skills.",
                display_type="info",
            )

        return CommandResult(
            success=True,
            message="Select a skill to load/unload",
            ui_config=UIConfig(
                type="modal",
                title=modal_definition["title"],
                width=modal_definition.get("width"),
                height=modal_definition.get("height"),
                modal_config=modal_definition,
            ),
            display_type="modal",
        )

    async def _show_create_skill_modal(self) -> CommandResult:
        """Show create skill form modal for active agent.

        Returns:
            Command result with modal UI.
        """
        active_agent = self.agent_manager.get_active_agent()
        if not active_agent:
            return CommandResult(
                success=False,
                message="No active agent. Use /agent <name> first.",
                display_type="error",
            )

        modal_definition = self._get_create_skill_modal_definition(active_agent.name)

        return CommandResult(
            success=True,
            message="Create a new skill",
            ui_config=UIConfig(
                type="modal",
                title=modal_definition.get("title", "Create Skill"),
                width=modal_definition.get("width"),
                height=modal_definition.get("height"),
                modal_config=modal_definition,
            ),
            display_type="modal",
        )

    async def _load_skill(self, skill_name: str) -> CommandResult:
        """Load a skill into active agent.

        Args:
            skill_name: Name of skill to load.

        Returns:
            Command result.
        """
        agent = self.agent_manager.get_active_agent()
        skill = agent.get_skill(skill_name) if agent else None
        if skill and self.agent_manager.load_skill(skill_name):
            # Inject skill content as user message
            if self.llm_service:
                skill_message = f"## Skill: {skill_name}\n\n{skill.content}"
                self.llm_service._add_conversation_message("user", skill_message)
            return CommandResult(
                success=True,
                message=f"Loaded skill: {skill_name}",
                display_type="success",
            )
        else:
            active_agent = self.agent_manager.get_active_agent()
            available_list = (
                "\n  ".join(s.name for s in active_agent.list_skills())
                if active_agent
                else "(none)"
            )
            return CommandResult(
                success=False,
                message=f"Skill not found: {skill_name}\nAvailable:\n  {available_list}",
                display_type="error",
            )

    async def _unload_skill(self, skill_name: str) -> CommandResult:
        """Unload a skill from active agent.

        Args:
            skill_name: Name of skill to unload.

        Returns:
            Command result.
        """
        if self.agent_manager.unload_skill(skill_name):
            # Add message indicating skill was unloaded
            if self.llm_service:
                self.llm_service._add_conversation_message(
                    "user",
                    f"[Skill '{skill_name}' has been unloaded - please disregard its instructions]",
                )
            return CommandResult(
                success=True,
                message=f"Unloaded skill: {skill_name}",
                display_type="success",
            )
        else:
            return CommandResult(
                success=False,
                message=f"Skill not loaded: {skill_name}",
                display_type="error",
            )

    def _build_skill_generation_prompt(
        self, agent_name: str, skill_name: str, description: str
    ) -> str:
        """Build prompt for LLM-powered skill generation.

        Args:
            agent_name: Name of the agent this skill belongs to.
            skill_name: Skill name (filename without .md).
            description: What the skill helps with.

        Returns:
            Prompt string for the LLM to generate the skill file.
        """
        # Get agent's actual directory (could be local or global)
        agent_dir = f".kollabor-cli/agents/{agent_name}"  # default fallback
        if self.agent_manager:
            agent = self.agent_manager.get_agent(agent_name)
            if agent:
                agent_dir = str(agent.directory)

        return f"""Create a new skill called "{skill_name}" for the "{agent_name}" agent.

The skill should help with: {description}

IMPORTANT: First, review existing skills to understand the format and style:
- Read {agent_dir}/system_prompt.md (to understand the agent's purpose)
- Read ~/.kollabor-cli/agents/default/debugging.md (an example skill file format)
- Read any existing .md skill files in {agent_dir}/ for format reference

After reviewing, create a comprehensive skill file that:
1. Starts with HTML comment description: <!-- {skill_name} - {description} -->
2. Has a clear header with skill name
3. Includes PHASE 0: Environment/context verification
4. Has multiple phases with detailed, actionable guidance
5. Includes examples and code snippets where relevant
6. Ends with a "Mandatory Rules" or "Quality Checklist" section
7. Is comprehensive (500+ lines) with real, actionable content

CRITICAL: Use @@@FILE/@@@END blocks to generate the file. This protects your content
from being parsed as actual tool calls. The format is:



Generate ONE comprehensive skill file using the @@@FILE block. Match the quality and depth of existing default agent skills."""

    def _get_create_skill_modal_definition(self, agent_name: str) -> Dict[str, Any]:
        """Get modal definition for creating a new skill."""
        short_path = f"agents/{agent_name}/<name>.md"

        return {
            "title": f"Create Skill - {agent_name}",
            "footer": "Ctrl+S: create • Esc: cancel",
            "form_action": "create_skill_submit",
            "sections": [
                {
                    "title": "New Skill",
                    "widgets": [
                        {
                            "type": "text_input",
                            "label": "Name",
                            "field": "name",
                            "placeholder": "my-skill",
                            "help": "Creates <name>.md in agent directory",
                        },
                        {
                            "type": "text_input",
                            "label": "Description",
                            "field": "description",
                            "placeholder": "What this skill helps with...",
                            "help": "AI generates comprehensive skill from this",
                        },
                    ],
                },
                {
                    "title": "Info",
                    "widgets": [
                        {
                            "type": "label",
                            "label": "Location",
                            "value": short_path,
                            "help": "AI generates detailed skill content",
                        },
                    ],
                },
            ],
            "actions": [
                {
                    "key": "Ctrl+S",
                    "label": "Create",
                    "action": "submit",
                    "style": "primary",
                },
                {
                    "key": "Escape",
                    "label": "Cancel",
                    "action": "cancel",
                    "style": "secondary",
                },
            ],
        }

    def _get_edit_skill_modal_definition(
        self, agent_name: str, skill_name: str
    ) -> Optional[Dict[str, Any]]:
        """Get modal definition for editing an existing skill."""
        if not self.agent_manager:
            return None

        active_agent = self.agent_manager.get_active_agent()
        if not active_agent or active_agent.name != agent_name:
            return None

        # Find the skill
        skill = None
        for s in active_agent.list_skills():
            if s.name == skill_name:
                skill = s
                break

        if not skill:
            return None

        # Short path for display
        short_path = f"agents/{agent_name}/{skill_name}.md"

        return {
            "title": f"Edit Skill: {skill_name}",
            "footer": "Tab navigate • Ctrl+S save • Esc cancel",
            "form_action": "edit_skill_submit",
            "edit_skill_name": skill_name,
            "sections": [
                {
                    "title": "Skill Settings",
                    "widgets": [
                        {
                            "type": "text_input",
                            "label": "Name",
                            "field": "name",
                            "value": skill_name,
                            "placeholder": "my-skill",
                            "help": "Rename the skill file",
                        },
                    ],
                },
                {
                    "title": "File",
                    "widgets": [
                        {
                            "type": "label",
                            "label": "Path",
                            "value": short_path,
                            "help": "nano or vim to edit",
                        },
                    ],
                },
            ],
            "actions": [
                {
                    "key": "Ctrl+S",
                    "label": "Save",
                    "action": "submit",
                    "style": "primary",
                },
                {
                    "key": "Escape",
                    "label": "Cancel",
                    "action": "cancel",
                    "style": "secondary",
                },
            ],
        }

    def _get_delete_skill_confirm_modal(
        self, agent_name: str, skill_name: str
    ) -> Optional[Dict[str, Any]]:
        """Get modal definition for delete skill confirmation."""
        if not self.agent_manager:
            return None

        active_agent = self.agent_manager.get_active_agent()
        if not active_agent or active_agent.name != agent_name:
            return None

        # Find the skill
        skill = None
        for s in active_agent.list_skills():
            if s.name == skill_name:
                skill = s
                break

        if not skill:
            return None

        is_loaded = skill_name in active_agent.active_skills
        warning_msg = ""
        if is_loaded:
            warning_msg = "\n\n[!] This skill is currently loaded."

        return {
            "title": f"Delete Skill: {skill_name}?",
            "footer": "Enter confirm • Esc cancel",
            "width": 60,
            "height": 12,
            "sections": [
                {
                    "title": "Confirm Deletion",
                    "commands": [
                        {
                            "name": f"Delete '{skill_name}'",
                            "description": f"{skill.description or skill.file_path.name}{warning_msg}",
                            "skill_name": skill_name,
                            "action": "delete_skill_confirm",
                        },
                        {
                            "name": "Cancel",
                            "description": "Keep the skill",
                            "action": "cancel",
                        },
                    ],
                }
            ],
            "actions": [
                {"key": "Enter", "label": "Confirm", "action": "select"},
                {"key": "Escape", "label": "Cancel", "action": "cancel"},
            ],
        }

    def _rename_skill_file(self, agent, original_name: str, new_name: str) -> bool:
        """Rename a skill file."""
        try:
            # Sanitize names
            if original_name.endswith(".md"):
                original_name = original_name[:-3]
            if new_name.endswith(".md"):
                new_name = new_name[:-3]

            # Same name = no-op success
            if original_name == new_name:
                return True

            original_path = agent.directory / f"{original_name}.md"
            new_path = agent.directory / f"{new_name}.md"

            if not original_path.exists():
                return False

            # Check new name doesn't exist
            if new_path.exists():
                return False

            # Rename file
            original_path.rename(new_path)
            return True
        except Exception:
            return False

    def _delete_skill_file(self, agent, skill_name: str) -> bool:
        """Delete a skill file from the agent directory."""
        try:
            # Sanitize name
            if skill_name.endswith(".md"):
                skill_name = skill_name[:-3]

            # Don't delete system_prompt.md
            if skill_name == "system_prompt":
                return False

            skill_path = agent.directory / f"{skill_name}.md"

            if not skill_path.exists():
                return False

            skill_path.unlink()
            return True
        except Exception:
            return False
