"""ievo uninstall — remove iEvo integration files from a project."""

from __future__ import annotations

import json
import re
from pathlib import Path

import typer

from ievo.commands.install import IEVO_LINE
from ievo.core.config import find_project_root
from ievo.utils.console import error, info, step, success

# Line regex — matches the sentinel line and surrounding blank lines
_IEVO_LINE_RE = re.compile(r"\n*Read `\.ievo/iEVO\.md` for pipeline conventions\.\n*")

# Files to remove (relative to project root)
_INTEGRATION_FILES = [
    ".claude/hooks/precompact_save.py",
]


def _clean_settings_local(path: Path) -> bool:
    """Remove iEvo hook entries from settings.local.json.

    Only removes the ``hooks.PreCompact`` entry that iEvo added.
    If the file becomes empty (no meaningful keys), it is deleted.
    Returns True if changes were made.
    """
    if not path.is_file():
        return False
    try:
        data = json.loads(path.read_text())
    except (json.JSONDecodeError, OSError):
        return False

    hooks = data.get("hooks")
    if not isinstance(hooks, dict) or "PreCompact" not in hooks:
        return False

    del hooks["PreCompact"]
    if not hooks:
        del data["hooks"]

    if not data:
        path.unlink()
    else:
        path.write_text(json.dumps(data, indent=2) + "\n")
    return True


def _unpatch_claude_md(path: Path) -> bool:
    """Remove iEvo reference line from CLAUDE.md.

    Returns True if the line was found and removed, False otherwise.
    """
    if not path.is_file():
        return False
    content = path.read_text()
    if IEVO_LINE not in content:
        return False
    new_content = _IEVO_LINE_RE.sub("\n", content)
    # Strip trailing whitespace but keep one trailing newline
    new_content = new_content.rstrip() + "\n" if new_content.strip() else ""
    path.write_text(new_content)
    return True


def uninstall(
    force: bool = typer.Option(
        False,
        "--force",
        help="Skip confirmation prompt.",
    ),
) -> None:
    """Remove iEvo integration files from the project.

    Removes Claude Code hooks, agent files, workflow files, and the
    CLAUDE.md marker block. Project data (.ievo/) is preserved.
    """
    root = find_project_root()
    if root is None:
        error("No iEvo project found in this directory or any parent.")
        raise typer.Exit(1)

    # Collect items to show
    claude_md = root / "CLAUDE.md"
    has_marker = claude_md.is_file() and IEVO_LINE in claude_md.read_text()

    settings_path = root / ".claude" / "settings.local.json"
    has_hook = False
    if settings_path.is_file():
        try:
            sdata = json.loads(settings_path.read_text())
            has_hook = "PreCompact" in sdata.get("hooks", {})
        except (json.JSONDecodeError, OSError):
            pass

    from ievo.core.config import IEVO_MANIFEST

    # manifest_path always exists — find_project_root() verified it
    manifest_path = root / IEVO_MANIFEST

    labels: list[str] = [".ievo/manifest.yaml"]
    if has_marker:
        labels.append("CLAUDE.md       patch block")
    if has_hook:
        labels.append(".claude/settings.local.json  (PreCompact hook only)")

    existing_files: list[str] = []
    for rel in _INTEGRATION_FILES:
        if (root / rel).is_file():
            existing_files.append(rel)
            labels.append(rel)

    # Agent .md files in .claude/agents/ — only remove bundled agents
    from ievo.marketplace import list_bundled_agents

    agents_dir = root / ".claude" / "agents"
    agent_files: list[Path] = []
    bundled_agent_names = set(list_bundled_agents())
    if agents_dir.is_dir():
        agent_files = sorted(p for p in agents_dir.glob("*.md") if p.stem in bundled_agent_names)
        for af in agent_files:
            labels.append(f".claude/agents/{af.name}")

    # Skills in .claude/skills/ — only remove bundled skills
    from ievo.marketplace import list_bundled_skills

    skills_dir = root / ".claude" / "skills"
    skill_subdirs: list[Path] = []
    bundled_skill_names = set(list_bundled_skills())
    if skills_dir.is_dir():
        skill_subdirs = sorted(
            p
            for p in skills_dir.iterdir()
            if p.is_dir() and p.name in bundled_skill_names and (p / "SKILL.md").exists()
        )
        for sd in skill_subdirs:
            labels.append(f".claude/skills/{sd.name}/SKILL.md")

    # Print summary
    info("[bold]Files to remove:[/bold]")
    for label in labels:
        step(label)

    if not force and not typer.confirm(
        "\nRemove iEvo integration?",
        default=False,
    ):
        raise typer.Exit(0)

    # Execute removals
    manifest_path.unlink()
    ievo_dir = root / ".ievo"
    if ievo_dir.is_dir() and not any(ievo_dir.iterdir()):
        ievo_dir.rmdir()
    step(".ievo/manifest.yaml removed")

    if has_marker:
        _unpatch_claude_md(claude_md)
        step("CLAUDE.md patch block removed")

    if has_hook:
        _clean_settings_local(settings_path)
        step("PreCompact hook removed from settings.local.json")

    for rel in existing_files:
        p = root / rel
        if p.is_file():
            p.unlink()

    for af in agent_files:
        if af.is_file():
            af.unlink()

    # Remove skills directories
    import shutil

    for sd in skill_subdirs:
        if sd.is_dir():
            shutil.rmtree(sd)

    # Remove .claude/skills/ dir if now empty
    if skills_dir.is_dir() and not any(skills_dir.iterdir()):
        skills_dir.rmdir()

    success("iEvo integration removed. Run ievo init to reinstall.")
