"""
Pre-commit hooks management commands.

Provides commands for installing and managing pre-commit hooks.
"""

import sys
from pathlib import Path
from typing import Any, Dict, List, Optional

import click
import yaml

from ...core.exceptions import PrompTrekError


def check_generated_command(ctx: click.Context, files: List[str]) -> None:
    """
    Check if files are generated by promptrek and should not be committed.

    Args:
        ctx: Click context
        files: List of file paths to check
    """
    # Check for local variables file first
    local_vars_files = [f for f in files if "variables.promptrek" in f]
    if local_vars_files:
        click.echo("❌ ERROR: Attempting to commit local variables file!", err=True)
        click.echo(
            "\nThe following file contains user-specific variables "
            "and should not be committed:",
            err=True,
        )
        for file_path in local_vars_files:
            click.echo(f"  - {file_path}", err=True)

        click.echo(
            "\n💡 This file should be:",
            err=True,
        )
        click.echo("   • Added to .gitignore (should already be there)", err=True)
        click.echo("   • Kept local to your machine", err=True)
        click.echo("   • Not shared in version control", err=True)

        click.echo("\nTo fix this:", err=True)
        click.echo(
            "1. Remove from staging: git reset HEAD variables.promptrek.yaml", err=True
        )
        click.echo("2. Ensure it's in .gitignore", err=True)
        click.echo("3. Only commit .promptrek.yaml source files", err=True)

        ctx.exit(1)

    generated_file_patterns = {
        # GitHub Copilot files
        ".github/copilot-instructions.md",
        ".github/instructions/*.instructions.md",
        ".github/prompts/*.prompt.md",
        # Cursor files
        ".cursorrules",
        ".cursor/rules/*.mdc",
        ".cursorignore",
        ".cursorindexingignore",
        "AGENTS.md",
        # Continue files
        "config.yaml",
        ".continue/config.json",
        ".continue/rules/*.md",
        # Claude files
        ".claude/*.md",
        "CLAUDE.md",
        # Cline files
        ".cline-rules/*.md",
        # Windsurf files
        ".windsurf/rules/*.md",
        # Kiro files
        ".kiro/steering/*.md",
        ".kiro/specs/*.md",
        # Tabnine files
        ".tabnine_commands",
        # Amazon Q files
        ".amazonq/rules/*.md",
        ".amazonq/cli-agents/*.json",
        # JetBrains AI files
        ".assistant/rules/*.md",
    }

    def matches_pattern(file_path: str, pattern: str) -> bool:
        """Check if a file path matches a pattern (supports simple wildcards)."""
        path = Path(file_path)

        # Normalize path to use forward slashes for cross-platform compatibility
        normalized_path = str(path).replace("\\", "/")

        # Direct match
        if normalized_path == pattern or normalized_path == pattern.rstrip("/"):
            return True

        # Directory match
        if pattern.endswith("/"):
            return normalized_path.startswith(pattern) or any(
                parent.name == pattern.rstrip("/") for parent in path.parents
            )

        # Wildcard match
        if "*" in pattern:
            pattern_parts = pattern.split("/")
            path_parts = normalized_path.split("/")

            if len(pattern_parts) != len(path_parts):
                return False

            for pattern_part, path_part in zip(pattern_parts, path_parts):
                if pattern_part == "*":
                    continue
                elif pattern_part.endswith("*"):
                    if not path_part.startswith(pattern_part[:-1]):
                        return False
                elif pattern_part.startswith("*"):
                    if not path_part.endswith(pattern_part[1:]):
                        return False
                elif "*" in pattern_part:
                    prefix, suffix = pattern_part.split("*", 1)
                    if not (
                        path_part.startswith(prefix) and path_part.endswith(suffix)
                    ):
                        return False
                elif pattern_part != path_part:
                    return False
            return True

        return False

    generated_files = []
    for file_path in files:
        for pattern in generated_file_patterns:
            if matches_pattern(file_path, pattern):
                generated_files.append(file_path)
                break

    if generated_files:
        click.echo("❌ ERROR: Attempting to commit generated prompt files!", err=True)
        click.echo(
            "\nThe following files appear to be generated by promptrek "
            "and should not be committed:",
            err=True,
        )
        for file_path in generated_files:
            click.echo(f"  - {file_path}", err=True)

        click.echo(
            "\n💡 These files are generated from .promptrek.yaml files and should be:",
            err=True,
        )
        click.echo("   • Added to .gitignore", err=True)
        click.echo("   • Generated locally as needed", err=True)
        click.echo("   • Not committed to version control", err=True)

        click.echo("\nTo fix this:", err=True)
        click.echo(
            "1. Remove these files from staging: git reset HEAD <file>", err=True
        )
        click.echo("2. Add them to .gitignore if not already there", err=True)
        click.echo("3. Commit only your .promptrek.yaml source files", err=True)

        ctx.exit(1)


def install_hooks_command(
    ctx: click.Context,
    config_file: Optional[Path],
    force: bool,
    activate: bool,
) -> None:
    """
    Install PrompTrek pre-commit hooks.

    Safely merges hooks into existing .pre-commit-config.yaml or creates new config.

    Args:
        ctx: Click context
        config_file: Path to pre-commit config file (defaults to .pre-commit-config.yaml)
        force: Overwrite existing hooks without confirmation
        activate: Run 'pre-commit install' to activate hooks in git
    """
    verbose = ctx.obj.get("verbose", False)

    # Default config file location
    if config_file is None:
        config_file = Path(".pre-commit-config.yaml")

    # Check if config exists
    config_exists = config_file.exists()

    if verbose:
        click.echo(f"Pre-commit config: {config_file}")
        click.echo(f"Config exists: {config_exists}")

    # Load existing config or create new one
    if config_exists:
        try:
            with open(config_file, "r") as f:
                config = yaml.safe_load(f) or {}
        except Exception as e:
            raise PrompTrekError(f"Failed to read existing config: {e}")
    else:
        config = {"repos": []}

    # Ensure repos key exists
    if "repos" not in config:
        config["repos"] = []

    # Check if PrompTrek hooks already exist
    # Look for repos with promptrek hook IDs
    promptrek_repo_index = None
    for i, repo in enumerate(config["repos"]):
        if isinstance(repo, dict) and "hooks" in repo:
            hook_ids = [h.get("id", "") for h in repo.get("hooks", [])]
            if (
                "promptrek-validate" in hook_ids
                or "promptrek-prevent-generated" in hook_ids
            ):
                promptrek_repo_index = i
                break

    # PrompTrek hook configuration
    # Note: For PrompTrek development, use "uv run promptrek" to use local version
    # For users installing PrompTrek, "promptrek" is sufficient
    entry_prefix = "uv run " if Path("pyproject.toml").exists() else ""

    promptrek_hooks = {
        "repo": "local",
        "hooks": [
            {
                "id": "promptrek-validate",
                "name": "Validate PrompTrek files",
                "entry": f"{entry_prefix}promptrek validate",
                "language": "system",
                "files": r"\.promptrek\.ya?ml$",
                "pass_filenames": True,
                "stages": ["pre-commit"],
            },
            {
                "id": "promptrek-prevent-generated",
                "name": "Prevent committing generated files",
                "entry": f"{entry_prefix}promptrek check-generated",
                "language": "system",
                "files": r"(?x)("
                r"^\.github/(copilot-instructions\.md|instructions/.*\.instructions\.md|prompts/.*\.prompt\.md)$|"
                r"^(\.cursorrules|\.cursor/.*|\.cursorignore|\.cursorindexingignore|AGENTS\.md)$|"
                r"^(config\.yaml|\.continue/.*)$|"
                r"^(\.claude/.*|CLAUDE\.md)$|"
                r"^\.clinerules/.*$|"
                r"^\.windsurf/.*$|"
                r"^\.kiro/.*$|"
                r"^\.tabnine_commands$|"
                r"^\.amazonq/.*$|"
                r"^\.assistant/.*"
                r")",
                "stages": ["pre-commit"],
                "always_run": False,
                "pass_filenames": True,
            },
            {
                "id": "promptrek-check-local-vars",
                "name": "Prevent committing local variables",
                "entry": f"{entry_prefix}promptrek check-generated",
                "language": "system",
                "files": r"variables\.promptrek\.ya?ml$",
                "stages": ["pre-commit"],
                "always_run": False,
                "pass_filenames": True,
            },
        ],
    }

    # Update or add PrompTrek hooks
    if promptrek_repo_index is not None:
        if not force:
            click.echo("⚠️  PrompTrek hooks already configured.")
            if not click.confirm("Do you want to update them?"):
                click.echo("Skipped.")
                return

        config["repos"][promptrek_repo_index] = promptrek_hooks
        action = "Updated"
    else:
        config["repos"].append(promptrek_hooks)
        action = "Added"

    # Write config file
    try:
        with open(config_file, "w") as f:
            yaml.dump(config, f, default_flow_style=False, sort_keys=False)

        click.echo(f"✅ {action} PrompTrek hooks to {config_file}")

        # Optionally activate hooks by running pre-commit install
        if activate:
            import shutil
            import subprocess

            # Check if pre-commit is available
            if shutil.which("pre-commit") is None:
                click.echo(
                    "\n⚠️  pre-commit command not found. Install it first:",
                    err=True,
                )
                click.echo("   pip install pre-commit", err=True)
                ctx.exit(1)

            try:
                click.echo("\n🔧 Running pre-commit install...")
                result = subprocess.run(
                    ["pre-commit", "install"],
                    capture_output=True,
                    text=True,
                    check=True,
                )

                if verbose and result.stdout:
                    click.echo(result.stdout)

                click.echo("✅ Git hooks activated successfully!")
                click.echo("\n💡 Hooks will now run automatically on git commit")
                click.echo("   Run manually: pre-commit run --all-files")

            except subprocess.CalledProcessError as e:
                click.echo(f"\n⚠️  Failed to run pre-commit install: {e}", err=True)
                if e.stderr:
                    click.echo(e.stderr, err=True)
                click.echo("\nYou can run it manually: pre-commit install")
        else:
            # Show next steps if not activating
            if not config_exists:
                click.echo("\n📝 Next steps:")
                click.echo("1. Install pre-commit: pip install pre-commit")
                click.echo("2. Install hooks: pre-commit install")
                click.echo("3. (Optional) Run on all files: pre-commit run --all-files")
            else:
                click.echo("\n💡 Hooks are configured. Run to apply:")
                click.echo("   pre-commit install")

    except Exception as e:
        raise PrompTrekError(f"Failed to write config: {e}")
