"""
Module: claude_env
Description: Shared Claude Code environment setup for pack and dashboard scaffolding

Implements:
    - docs/cli/reference.md#huitzo-pack-new
    - docs/cli/reference.md#huitzo-dashboard-new
"""

import json
import platform
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Literal

import typer
from rich.console import Console

console = Console()

_CLAUDE_ENV_REPO = "https://github.com/Huitzo-Inc/pack-claude-env.git"
_CLAUDE_ENV_MANUAL_URL = "https://github.com/Huitzo-Inc/pack-claude-env"

Profile = Literal["pack-only", "dashboard-only", "full-stack"]

# What each profile provides (for display in success message)
_PROFILE_INFO: dict[str, dict[str, list[str]]] = {
    "pack-only": {
        "skills": [
            "/draft-spec",
            "/draft-docs",
            "/add-command",
            "/test-pack",
            "/validate-pack",
            "/lint-and-fix",
        ],
        "agents": ["docs-writer", "pack-developer", "pack-reviewer", "spec-architect"],
    },
    "dashboard-only": {
        "skills": [
            "/draft-spec",
            "/scaffold-dashboard",
            "/test-dashboard",
            "/validate-dashboard",
            "/dashboard-dev",
            "/lint-and-fix",
        ],
        "agents": ["docs-writer", "dashboard-developer", "dashboard-reviewer", "spec-architect"],
    },
    "full-stack": {
        "skills": [
            "/draft-spec",
            "/draft-docs",
            "/add-command",
            "/scaffold-dashboard",
            "/test-pack",
            "/test-dashboard",
            "/validate-pack",
            "/validate-dashboard",
            "/lint-and-fix",
        ],
        "agents": [
            "docs-writer",
            "pack-developer",
            "pack-reviewer",
            "dashboard-developer",
            "dashboard-reviewer",
            "spec-architect",
        ],
    },
}


def prompt_claude_setup(
    project_root: Path,
    default_profile: Profile,
    has_venv: bool = False,
) -> None:
    """Prompt the user to set up a Claude Code environment.

    Args:
        project_root: Root directory of the project
        default_profile: Default profile based on project type
        has_venv: Whether the project has a Python venv (for MCP server install)
    """
    console.print()
    if not typer.confirm(
        "Would you like to set up a Claude Code environment? (requires git)",
        default=False,
    ):
        return

    if not shutil.which("git"):
        console.print(
            f"[yellow]⚠ git is not installed. Install manually: {_CLAUDE_ENV_MANUAL_URL}[/yellow]"
        )
        return

    # Profile selection
    profile = _select_profile(default_profile)

    _clone_and_install(project_root, profile, has_venv)


def _select_profile(default_profile: Profile) -> Profile:
    """Let the user pick a Claude Code environment profile."""
    profiles: list[Profile] = ["pack-only", "dashboard-only", "full-stack"]

    console.print("\n[bold]Select a Claude Code environment profile:[/bold]")
    for i, p in enumerate(profiles, 1):
        marker = " [green](default)[/green]" if p == default_profile else ""
        if p == "pack-only":
            desc = "Python Intelligence Pack commands only"
        elif p == "dashboard-only":
            desc = "React dashboard micro-frontend only"
        else:
            desc = "Both pack + dashboard development"
        console.print(f"  [{i}] {p} — {desc}{marker}")

    default_num = profiles.index(default_profile) + 1
    choice = typer.prompt(
        "Profile",
        default=str(default_num),
    )

    try:
        idx = int(choice) - 1
        if 0 <= idx < len(profiles):
            return profiles[idx]
    except ValueError:
        # Try matching by name
        choice_lower = choice.strip().lower()
        for p in profiles:
            if p == choice_lower:
                return p

    console.print(f"[yellow]⚠ Invalid choice, using default: {default_profile}[/yellow]")
    return default_profile


def _clone_and_install(
    project_root: Path,
    profile: Profile,
    has_venv: bool,
) -> None:
    """Clone the Claude Code environment repo, apply profile, and install."""
    tmp_dir = None
    try:
        tmp_dir = tempfile.mkdtemp(prefix="pack-claude-env-")
        result = subprocess.run(
            ["git", "clone", "--depth", "1", "--branch", "main", _CLAUDE_ENV_REPO, tmp_dir],
            capture_output=True,
            text=True,
            check=False,
            timeout=30,
        )
        if result.returncode != 0:
            console.print(
                "[yellow]⚠ Could not clone Claude Code environment. "
                f"Install manually: {_CLAUDE_ENV_MANUAL_URL}[/yellow]"
            )
            return

        tmp_path = Path(tmp_dir)

        # Safety: reject symlinks in cloned content (defense against compromised upstream)
        src_claude = tmp_path / "claude"
        if src_claude.is_dir():
            for item in src_claude.rglob("*"):
                if item.is_symlink():
                    console.print(
                        "[yellow]⚠ Symlink found in cloned environment, aborting. "
                        f"Install manually: {_CLAUDE_ENV_MANUAL_URL}[/yellow]"
                    )
                    return

        # Apply profile filtering
        _apply_profile(tmp_path, project_root, profile)

        # Copy CONSTITUTION.md
        src_constitution = tmp_path / "CONSTITUTION.md"
        dst_constitution = project_root / "CONSTITUTION.md"
        if src_constitution.is_file():
            shutil.copy2(src_constitution, dst_constitution)

        # Install docs MCP server if project has a Python venv
        if has_venv:
            _install_docs_mcp(project_root)

        # Display success
        info = _PROFILE_INFO[profile]
        console.print(f"\n[green]✅ Claude Code environment set up! (profile: {profile})[/green]")
        console.print(f"[dim]  Available skills: {', '.join(info['skills'])}[/dim]")
        console.print(f"[dim]  Available agents: {', '.join(info['agents'])}[/dim]")
        if has_venv:
            console.print(
                "[dim]  Documentation server: your-docs-mcp (serves docs/ to Claude Code)[/dim]"
            )

    except subprocess.TimeoutExpired:
        console.print(
            f"[yellow]⚠ Clone timed out. Install manually: {_CLAUDE_ENV_MANUAL_URL}[/yellow]"
        )
    except (OSError, subprocess.SubprocessError, json.JSONDecodeError, ValueError):
        console.print(
            "[yellow]⚠ Could not set up Claude Code environment. "
            f"Install manually: {_CLAUDE_ENV_MANUAL_URL}[/yellow]"
        )
    finally:
        if tmp_dir:
            shutil.rmtree(tmp_dir, ignore_errors=True)


def _apply_profile(
    tmp_path: Path,
    project_root: Path,
    profile: Profile,
) -> None:
    """Copy claude/ directory, filtering files based on the selected profile."""
    src_claude = tmp_path / "claude"
    dst_claude = project_root / ".claude"

    if not src_claude.is_dir():
        return

    # Load profile definition
    profile_file = tmp_path / "profiles" / f"{profile}.json"
    if profile == "full-stack" or not profile_file.exists():
        # Full-stack: copy everything
        shutil.copytree(src_claude, dst_claude, dirs_exist_ok=True)
        return

    profile_data = json.loads(profile_file.read_text())
    exclude_patterns = profile_data.get("files", {}).get("exclude", [])

    # Copy with exclusion filter
    def _ignore_fn(directory: str, contents: list[str]) -> list[str]:
        """Return names to ignore in this directory."""
        ignored = []
        rel_dir = Path(directory).relative_to(src_claude)
        for name in contents:
            rel_path = str(rel_dir / name) if str(rel_dir) != "." else name
            # Prefix with claude/ to match profile paths
            full_rel = f"claude/{rel_path}"
            for pattern in exclude_patterns:
                stripped = pattern.rstrip("/")
                if full_rel == stripped or full_rel.startswith(stripped + "/"):
                    ignored.append(name)
                    break
        return ignored

    shutil.copytree(src_claude, dst_claude, ignore=_ignore_fn, dirs_exist_ok=True)


def _install_docs_mcp(project_root: Path) -> None:
    """Install your-docs-mcp in the pack's virtual environment."""
    if platform.system() == "Windows":
        pip_path = project_root / "venv" / "Scripts" / "pip"
    else:
        pip_path = project_root / "venv" / "bin" / "pip"

    if not pip_path.exists():
        return

    try:
        result = subprocess.run(
            [str(pip_path), "install", "your-docs-mcp"],
            capture_output=True,
            text=True,
            check=False,
            timeout=60,
        )
        if result.returncode == 0:
            console.print("[green]✅ Documentation server (your-docs-mcp) installed[/green]")
        else:
            console.print(
                "[yellow]⚠ Could not install your-docs-mcp. "
                "Install manually: pip install your-docs-mcp[/yellow]"
            )
    except subprocess.TimeoutExpired:
        console.print(
            "[yellow]⚠ your-docs-mcp install timed out. "
            "Install manually: pip install your-docs-mcp[/yellow]"
        )
