"""Install cleave skill to Claude Code skills directory.

This module handles finding the package's skill directory and creating
a symlink in ~/.claude/skills/cleave.

TODO: Refactor to support multiple agentic interfaces beyond Claude Code.
      The current implementation is Claude Code specific (~/.claude/skills/).
      Future interfaces may use different discovery paths:
      - Cursor: ~/.cursor/skills/ or similar
      - Windsurf: ~/.windsurf/skills/ or similar
      - Generic MCP: ~/.config/mcp-skills/ or similar
      Consider an interface registry or plugin pattern.
"""

from __future__ import annotations

import importlib.resources
from dataclasses import dataclass
from pathlib import Path
from typing import Literal


@dataclass
class InstallResult:
    """Result of skill installation attempt."""

    success: bool
    action: Literal["created", "updated", "skipped", "error"]
    message: str
    source_path: Path | None
    target_path: Path | None


def find_package_skill_dir() -> Path | None:
    """Find the skill directory within the installed cleave package.

    Works with pip installs, pipx installs, and editable installs.

    Returns:
        Path to the skill directory, or None if not found.
    """
    try:
        # Use importlib.resources to find the package location
        # This works regardless of install method (pip, pipx, editable)
        with importlib.resources.as_file(
            importlib.resources.files("cleave").joinpath("skill")
        ) as skill_path:
            if skill_path.exists() and skill_path.is_dir():
                return skill_path.resolve()
    except (TypeError, FileNotFoundError):
        pass

    # Fallback: try to find via __file__ (works for editable installs)
    try:
        import cleave

        package_dir = Path(cleave.__file__).parent
        skill_dir = package_dir / "skill"
        if skill_dir.exists() and skill_dir.is_dir():
            return skill_dir.resolve()
    except (AttributeError, TypeError):
        pass

    return None


def install_skill(home_dir: Path | None = None) -> InstallResult:
    """Install the cleave skill by creating a symlink.

    Creates a symlink at ~/.claude/skills/cleave pointing to the
    skill directory within the installed package.

    Args:
        home_dir: Override home directory (for testing). Defaults to Path.home().

    Returns:
        InstallResult with success status and details.
    """
    if home_dir is None:
        home_dir = Path.home()

    skills_dir = home_dir / ".claude" / "skills"
    target_path = skills_dir / "cleave"

    # Find the source skill directory
    source_path = find_package_skill_dir()
    if source_path is None:
        return InstallResult(
            success=False,
            action="error",
            message="Could not find skill directory in cleave package",
            source_path=None,
            target_path=target_path,
        )

    # Validate resolved path stays within home directory (defense against symlink attacks)
    resolved_skills_dir = skills_dir.resolve()
    resolved_home = home_dir.resolve()
    if not str(resolved_skills_dir).startswith(str(resolved_home) + "/") and resolved_skills_dir != resolved_home:
        return InstallResult(
            success=False,
            action="error",
            message=f"Path escapes home directory: {resolved_skills_dir}",
            source_path=source_path,
            target_path=target_path,
        )

    # Create parent directories if needed
    skills_dir.mkdir(parents=True, exist_ok=True)

    # Check what exists at target path
    if target_path.exists() or target_path.is_symlink():
        if target_path.is_symlink():
            # It's a symlink - check where it points
            try:
                current_target = target_path.resolve()
                if current_target == source_path:
                    return InstallResult(
                        success=True,
                        action="skipped",
                        message=f"Skill already installed correctly at {target_path}",
                        source_path=source_path,
                        target_path=target_path,
                    )
                else:
                    # Points elsewhere - update it
                    # Use try/except to handle TOCTOU race condition
                    try:
                        target_path.unlink()
                        target_path.symlink_to(source_path)
                    except FileExistsError:
                        # Race condition: something appeared between unlink and symlink
                        return InstallResult(
                            success=False,
                            action="error",
                            message=f"Race condition: {target_path} was modified during update. Retry.",
                            source_path=source_path,
                            target_path=target_path,
                        )
                    return InstallResult(
                        success=True,
                        action="updated",
                        message=f"Updated symlink from {current_target} to {source_path}",
                        source_path=source_path,
                        target_path=target_path,
                    )
            except OSError:
                # Broken symlink - remove and recreate
                try:
                    target_path.unlink()
                    target_path.symlink_to(source_path)
                except FileExistsError:
                    return InstallResult(
                        success=False,
                        action="error",
                        message=f"Race condition: {target_path} was modified during update. Retry.",
                        source_path=source_path,
                        target_path=target_path,
                    )
                return InstallResult(
                    success=True,
                    action="updated",
                    message=f"Replaced broken symlink with link to {source_path}",
                    source_path=source_path,
                    target_path=target_path,
                )
        elif target_path.is_dir():
            return InstallResult(
                success=False,
                action="error",
                message=f"Directory exists at {target_path}. Remove it manually to install skill.",
                source_path=source_path,
                target_path=target_path,
            )
        elif target_path.is_file():
            return InstallResult(
                success=False,
                action="error",
                message=f"File exists at {target_path}. Remove it manually to install skill.",
                source_path=source_path,
                target_path=target_path,
            )

    # Create the symlink
    try:
        target_path.symlink_to(source_path)
    except FileExistsError:
        # Race condition: something appeared between existence check and symlink
        return InstallResult(
            success=False,
            action="error",
            message=f"Race condition: {target_path} was created during install. Retry.",
            source_path=source_path,
            target_path=target_path,
        )
    return InstallResult(
        success=True,
        action="created",
        message=f"Installed skill symlink: {target_path} -> {source_path}",
        source_path=source_path,
        target_path=target_path,
    )
