"""Shared base for agent types that provision a Claude skill."""

from __future__ import annotations

from pathlib import Path
from typing import ClassVar

import click
from loguru import logger

from imbue.imbue_common.logging import log_span
from imbue.mng.agents.default_plugins.claude_agent import ClaudeAgent
from imbue.mng.agents.default_plugins.claude_agent import ClaudeAgentConfig
from imbue.mng.config.data_types import MngContext
from imbue.mng.interfaces.host import CreateAgentOptions
from imbue.mng.interfaces.host import OnlineHostInterface


class SkillProvisionedAgentConfig(ClaudeAgentConfig):
    """Config for agent types that provision a Claude skill.

    Subclass this for each skill-provisioned agent type to get a distinct
    config class for the agent registry.
    """


def _prompt_user_for_skill_install(skill_name: str, skill_path: Path) -> bool:
    """Prompt the user to install or update a skill."""
    if skill_path.exists():
        logger.info(
            "\nThe {} skill at {} will be updated.\n",
            skill_name,
            skill_path,
        )
        return click.confirm(f"Update the {skill_name} skill?", default=True)
    else:
        logger.info(
            "\nThe {} skill will be installed to {}.\n",
            skill_name,
            skill_path,
        )
        return click.confirm(f"Install the {skill_name} skill?", default=True)


def _install_skill_locally(skill_name: str, skill_content: str, mng_ctx: MngContext) -> None:
    """Install a skill to the local user's ~/.claude/skills/."""
    skill_path = Path.home() / ".claude" / "skills" / skill_name / "SKILL.md"

    with log_span("Installing {} skill to {}", skill_name, skill_path):
        # Skip if the skill is already installed with the same content
        if skill_path.exists() and skill_path.read_text() == skill_content:
            logger.debug("{} skill is already up to date at {}", skill_name, skill_path)
            return

        if mng_ctx.is_interactive and not mng_ctx.is_auto_approve:
            if not _prompt_user_for_skill_install(skill_name, skill_path):
                logger.info("Skipped {} skill installation", skill_name)
                return

        skill_path.parent.mkdir(parents=True, exist_ok=True)
        skill_path.write_text(skill_content)
        logger.debug("Installed {} skill to {}", skill_name, skill_path)


def _install_skill_remotely(skill_name: str, skill_content: str, host: OnlineHostInterface) -> None:
    """Install a skill on a remote host."""
    skill_path = Path(f".claude/skills/{skill_name}/SKILL.md")

    with log_span("Installing {} skill on remote host", skill_name):
        host.execute_command(
            f"mkdir -p ~/.claude/skills/{skill_name}",
            timeout_seconds=10.0,
        )
        host.write_text_file(skill_path, skill_content)
        logger.debug("Installed {} skill on remote host", skill_name)


class SkillProvisionedAgent(ClaudeAgent):
    """Base agent that provisions a Claude skill during setup.

    Subclasses must set the _skill_name and _skill_content class variables
    to define which skill to install.
    """

    _skill_name: ClassVar[str]
    _skill_content: ClassVar[str]

    def provision(
        self,
        host: OnlineHostInterface,
        options: CreateAgentOptions,
        mng_ctx: MngContext,
    ) -> None:
        """Run standard Claude provisioning, then install the skill."""
        super().provision(host, options, mng_ctx)

        if host.is_local:
            _install_skill_locally(self._skill_name, self._skill_content, mng_ctx)
        else:
            _install_skill_remotely(self._skill_name, self._skill_content, host)
