"""Update/diff mechanism for TokenGuard.

Compares installed files against current templates, preserving user
customizations via hash comparison.
"""

import json
from pathlib import Path
from typing import Optional

from . import __version__
from .scaffold import _hash_content


def _get_current_template_hashes(project_dir: Path) -> dict:
    """Get content hashes for what templates would generate now.

    Uses dry-run scaffold to generate template content without writing files,
    then hashes each file for comparison against installed versions.

    Args:
        project_dir: Root directory of the target project.

    Returns:
        Dict of relative_path -> content hash for all template-generated files.
    """
    from .scaffold import scaffold_project

    mirror_file = project_dir / ".claude" / ".tokenguard.json"
    tracking = json.loads(mirror_file.read_text(encoding="utf-8"))

    project_type = tracking.get("project_type", "generic")
    grip_global = tracking.get("grip_global", False)

    result = scaffold_project(
        project_dir=project_dir,
        project_type=project_type,
        standalone=not grip_global,
        dry_run=True,
    )

    template_hashes = {}
    for rel_path, content in result["files"].items():
        if ".tokenguard.json" in rel_path:
            continue
        template_hashes[rel_path] = _hash_content(content)

    return template_hashes


def check_updates(project_dir: Path) -> dict:
    """Check which files have available updates.

    Compares installed file hashes against current template hashes.
    Files modified by the user (hash mismatch with installed hash) are
    flagged as user-modified and skipped during update.

    Args:
        project_dir: Root directory of the target project.

    Returns:
        Dict with keys:
            - updatable: list of files that can be updated
            - user_modified: list of files modified by user (skipped)
            - current: list of files already up to date
            - missing_tracking: True if .tokenguard.json not found
    """
    mirror_file = project_dir / ".claude" / ".tokenguard.json"
    if not mirror_file.exists():
        return {"updatable": [], "user_modified": [], "current": [], "missing_tracking": True}

    try:
        tracking = json.loads(mirror_file.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, OSError):
        return {"updatable": [], "user_modified": [], "current": [], "missing_tracking": True}

    installed_hashes = tracking.get("file_hashes", {})

    # Get what templates would generate now
    try:
        template_hashes = _get_current_template_hashes(project_dir)
    except (json.JSONDecodeError, OSError):
        template_hashes = {}

    updatable = []
    user_modified = []
    current = []

    for rel_path, installed_hash in installed_hashes.items():
        full_path = project_dir / rel_path
        if not full_path.exists():
            updatable.append(rel_path)
            continue

        current_content = full_path.read_text(encoding="utf-8")
        current_hash = _hash_content(current_content)

        if current_hash != installed_hash:
            # User modified this file - don't overwrite
            user_modified.append(rel_path)
        else:
            # File matches installed hash - check if template has changed
            template_hash = template_hashes.get(rel_path)
            if template_hash and template_hash != installed_hash:
                updatable.append(rel_path)
            else:
                current.append(rel_path)

    return {
        "updatable": updatable,
        "user_modified": user_modified,
        "current": current,
        "missing_tracking": False,
    }


def apply_updates(project_dir: Path, updatable: list) -> list:
    """Apply template updates to specified files.

    Re-generates files from current templates and updates tracking hashes.

    Args:
        project_dir: Root directory of the target project.
        updatable: List of relative paths to update.

    Returns:
        List of files that were updated.
    """
    from .scaffold import scaffold_project

    mirror_file = project_dir / ".claude" / ".tokenguard.json"
    tracking = json.loads(mirror_file.read_text(encoding="utf-8"))

    project_type = tracking.get("project_type", "generic")
    grip_global = tracking.get("grip_global", False)

    # Generate fresh content via dry-run
    result = scaffold_project(
        project_dir=project_dir,
        project_type=project_type,
        standalone=not grip_global,
        dry_run=True,
    )

    applied = []
    file_hashes = tracking.get("file_hashes", {})

    for rel_path in updatable:
        if rel_path in result["files"]:
            content = result["files"][rel_path]
            full_path = project_dir / rel_path
            full_path.parent.mkdir(parents=True, exist_ok=True)
            full_path.write_text(content, encoding="utf-8")
            file_hashes[rel_path] = _hash_content(content)
            applied.append(rel_path)

    # Update tracking file
    tracking["file_hashes"] = file_hashes
    tracking["version"] = __version__
    mirror_file.write_text(json.dumps(tracking, indent=2) + "\n", encoding="utf-8")

    return applied


def get_status(project_dir: Path) -> Optional[dict]:
    """Get TokenGuard installation status.

    Args:
        project_dir: Root directory of the target project.

    Returns:
        Status dict or None if not initialized.
    """
    mirror_file = project_dir / ".claude" / ".tokenguard.json"
    if not mirror_file.exists():
        return None

    try:
        tracking = json.loads(mirror_file.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, OSError):
        return None

    return {
        "version": tracking.get("version", "unknown"),
        "project_type": tracking.get("project_type", "unknown"),
        "grip_global": tracking.get("grip_global", False),
        "installed_at": tracking.get("installed_at", "unknown"),
        "components": tracking.get("installed_components", []),
        "latest_version": __version__,
        "update_available": tracking.get("version") != __version__,
    }


def eject(project_dir: Path) -> list:
    """Remove TokenGuard tracking, leave files as user-owned.

    Args:
        project_dir: Root directory of the target project.

    Returns:
        List of actions taken.
    """
    actions = []
    mirror_file = project_dir / ".claude" / ".tokenguard.json"

    if mirror_file.exists():
        mirror_file.unlink()
        actions.append("Removed .tokenguard.json tracking file")

    # Remove hook registration from settings.json if it's Mirror-managed
    settings_file = project_dir / ".claude" / "settings.json"
    if settings_file.exists():
        try:
            settings = json.loads(settings_file.read_text(encoding="utf-8"))
            hooks = settings.get("hooks", {}).get("PreToolUse", [])
            new_hooks = []
            for hook_group in hooks:
                filtered = [
                    h for h in hook_group.get("hooks", [])
                    if "mirror-hook.py" not in h.get("command", "")
                ]
                if filtered:
                    hook_group["hooks"] = filtered
                    new_hooks.append(hook_group)
            if new_hooks != hooks:
                settings["hooks"]["PreToolUse"] = new_hooks
                settings_file.write_text(
                    json.dumps(settings, indent=2) + "\n", encoding="utf-8"
                )
                actions.append("Removed mirror-hook from settings.json")
        except (json.JSONDecodeError, OSError):
            pass

    if not actions:
        actions.append("No TokenGuard tracking found")

    return actions
