"""Internal helpers for ClaudeFilesStep - file filtering, categorization, and cleanup."""

from __future__ import annotations

import shutil
from pathlib import Path
from typing import Any

from installer.context import InstallContext
from installer.downloads import DownloadConfig

SKIP_PATTERNS = (
    "__pycache__",
    ".pyc",
    "/node_modules/",
    "/dist/",
    "/.vite/",
    "/coverage/",
    "/.turbo/",
    ".lock",
    "-lock.yaml",
    ".install-version",
)

SKIP_EXTENSIONS = (".png", ".jpg", ".jpeg", ".gif", ".webp")


def _should_skip_file(file_path: str, ctx: InstallContext, hooks_to_skip: list[str]) -> bool:
    """Check if a file should be skipped during installation."""
    if not file_path:
        return True

    if "/hooks/" in file_path and any(h in file_path for h in hooks_to_skip):
        return True

    if any(pattern in file_path for pattern in SKIP_PATTERNS):
        return True

    if file_path.endswith(SKIP_EXTENSIONS):
        return True
    if Path(file_path).name == ".gitignore":
        return True

    if not ctx.enable_python:
        if "file_checker_python.py" in file_path or "python-rules.md" in file_path:
            return True

    if not ctx.enable_typescript:
        if "file_checker_ts.py" in file_path or "typescript-rules.md" in file_path:
            return True

    if not ctx.enable_golang:
        if "file_checker_go.py" in file_path or "golang-rules.md" in file_path:
            return True

    return False


def _categorize_file(file_path: str) -> str:
    """Determine which category a file belongs to."""
    if file_path == "tribunal/settings.json" or file_path.endswith("/settings.json"):
        return "settings"
    elif "/commands/" in file_path:
        return "commands"
    elif "/rules/" in file_path:
        return "rules"
    else:
        return "sf_plugin"


def _clear_directory_safe(path: Path, ui: Any = None, error_msg: str = "") -> None:
    """Safely remove a directory with error handling."""
    if not path.exists():
        return
    try:
        shutil.rmtree(path)
    except (OSError, IOError) as e:
        if ui and error_msg:
            ui.warning(f"{error_msg}: {e}")


def _clear_directory_contents(path: Path) -> None:
    """Remove contents of a directory but keep the directory."""
    if not path.exists():
        return
    for item in path.iterdir():
        try:
            if item.is_dir():
                shutil.rmtree(item)
            else:
                item.unlink()
        except (OSError, IOError):
            pass


def _cleanup_legacy_standards_skills(plugin_dir: Path) -> None:
    """Remove old standards-* skill directories from plugin skills folder.

    Standards were migrated from tribunal/skills/ to tribunal/rules/ with frontmatter.
    Runs unconditionally to clean up stale installs.
    """
    skills_dir = plugin_dir / "skills"
    if not skills_dir.exists():
        return

    for item in skills_dir.iterdir():
        if item.is_dir() and item.name.startswith("standards-"):
            _clear_directory_safe(item)

    if skills_dir.exists() and not any(skills_dir.iterdir()):
        try:
            skills_dir.rmdir()
        except (OSError, IOError):
            pass


def _cleanup_legacy_project_dirs(ctx: InstallContext) -> None:
    """Remove legacy project-level directories."""
    project_claude_dir = ctx.project_dir / ".claude"

    _clear_directory_safe(project_claude_dir / "rules" / "standard")

    old_commands_dir = project_claude_dir / "commands"
    if old_commands_dir.exists():
        standard_commands = {"spec", "sync", "plan", "implement", "verify", "learn"}
        for cmd_file in old_commands_dir.iterdir():
            if cmd_file.is_file() and cmd_file.suffix == ".md":
                if cmd_file.stem in standard_commands:
                    try:
                        cmd_file.unlink()
                    except (OSError, IOError):
                        pass
        if old_commands_dir.exists() and not any(old_commands_dir.iterdir()):
            try:
                old_commands_dir.rmdir()
            except (OSError, IOError):
                pass

    for old_dir_name in ["pilot", "sf", "hooks", "scripts", "plugin"]:
        _clear_directory_safe(project_claude_dir / old_dir_name)

    old_custom_rules = project_claude_dir / "rules" / "custom"
    if old_custom_rules.exists() and old_custom_rules.is_dir():
        try:
            gitkeep = old_custom_rules / ".gitkeep"
            if gitkeep.exists():
                gitkeep.unlink()
            if not any(old_custom_rules.iterdir()):
                old_custom_rules.rmdir()
        except (OSError, IOError):
            pass


def _cleanup_old_directories(
    ctx: InstallContext,
    config: DownloadConfig,
    ui: Any,
) -> None:
    """Clean up old installation directories.

    Always cleans all directories - cleanup is decoupled from which file
    categories were found. Ensures stale files are removed even if specific
    categories are empty due to filtering or API issues.
    """
    home_claude_dir = Path.home() / ".claude"
    home_sf_plugin_dir = home_claude_dir / "tribunal"

    _cleanup_legacy_standards_skills(home_sf_plugin_dir)

    # Always remove old ~/.claude/pilot/ (pre-rebrand location),
    # regardless of source_is_destination — it's a HOME dir, not source.
    _clear_directory_safe(
        home_claude_dir / "pilot",
        ui,
        "Failed to clear legacy pilot directory",
    )

    # Also remove old ~/.claude/tribunal/ if present (previous rebrand).
    _clear_directory_safe(
        home_claude_dir / "sf",
        ui,
        "Failed to clear legacy sf directory",
    )

    source_is_destination = (
        config.local_mode and config.local_repo_dir and config.local_repo_dir.resolve() == ctx.project_dir.resolve()
    )
    if source_is_destination:
        return

    _clear_directory_safe(
        home_claude_dir / "commands",
        ui,
        "Failed to clear global commands directory",
    )

    _clear_directory_safe(
        home_claude_dir / "rules",
        ui,
        "Failed to clear global rules directory",
    )

    _clear_directory_contents(home_sf_plugin_dir)

    _cleanup_legacy_project_dirs(ctx)
