"""
Windsurf (Cascade) installation for Gobby hooks.

This module handles installing and uninstalling Gobby hooks for Windsurf.
"""

import json
import logging
import os
import tempfile
import time
from pathlib import Path
from shutil import copy2
from typing import Any

from gobby.cli.utils import get_install_dir

from .ide_config import configure_ide_terminal_title
from .shared import (
    clean_project_hooks,
    install_global_hooks,
    install_shared_content,
)

logger = logging.getLogger(__name__)


def install_windsurf(project_path: Path, mode: str = "global") -> dict[str, Any]:
    """Install Gobby integration for Windsurf (hooks, workflows).

    Args:
        project_path: Path to the project root
        mode: "global" installs hooks to ~/.gobby/hooks/ and settings to
            ~/.codeium/windsurf/hooks.json. "project" installs per-project (existing behavior).

    Returns:
        Dict with installation results including success status and installed items
    """
    hooks_installed: list[str] = []
    result: dict[str, Any] = {
        "success": False,
        "hooks_installed": hooks_installed,
        "workflows_installed": [],
        "error": None,
    }

    hooks_dir = Path.home() / ".gobby" / "hooks"
    if mode == "global":
        windsurf_path = Path.home() / ".codeium" / "windsurf"
    else:
        windsurf_path = project_path / ".windsurf"
    hooks_file = windsurf_path / "hooks.json"

    # Ensure directories exist
    windsurf_path.mkdir(parents=True, exist_ok=True)

    # Get source files
    install_dir = get_install_dir()
    windsurf_install_dir = install_dir / "windsurf"

    source_hooks_template = windsurf_install_dir / "hooks-template.json"

    if not source_hooks_template.exists():
        result["error"] = f"Missing source files: [{source_hooks_template}]"
        return result

    # Install hook files (always global)
    try:
        install_global_hooks()
        # Clean up project-level hooks to prevent double-firing
        cleaned = clean_project_hooks(project_path / ".windsurf" / "hooks.json")
        if cleaned:
            result["project_hooks_cleaned"] = cleaned
    except OSError as e:
        logger.error(f"Failed to install hook files: {e}")
        result["error"] = f"Failed to install hook files: {e}"
        return result

    # Install shared content (workflows) to .gobby/
    try:
        gobby_path = project_path / ".gobby"
        shared = install_shared_content(gobby_path, project_path)
        result["workflows_installed"] = shared.get("workflows", [])
        result["agents_installed"] = shared.get("agents", [])
        result["plugins_installed"] = shared.get("plugins", [])
        result["prompts_installed"] = shared.get("prompts", [])
        result["docs_installed"] = shared.get("docs", [])
    except Exception as e:
        logger.warning(f"Failed to install shared content: {e}")
        # Non-fatal - continue with hooks installation

    # Backup existing hooks.json if it exists
    backup_file = None
    if hooks_file.exists():
        timestamp = int(time.time())
        backup_file = windsurf_path / f"hooks.json.{timestamp}.backup"
        try:
            copy2(hooks_file, backup_file)
        except OSError as e:
            logger.error(f"Failed to create backup of hooks.json: {e}")
            result["error"] = f"Failed to create backup: {e}"
            return result

    # Load existing hooks or create empty
    existing_hooks: dict[str, Any] = {"hooks": {}}
    if hooks_file.exists():
        try:
            with open(hooks_file) as f:
                existing_hooks = json.load(f)
        except json.JSONDecodeError as e:
            logger.warning(f"Failed to parse hooks.json, starting fresh: {e}")
        except OSError as e:
            logger.error(f"Failed to read hooks.json: {e}")
            result["error"] = f"Failed to read hooks.json: {e}"
            return result

    # Ensure structure
    if "hooks" not in existing_hooks:
        existing_hooks["hooks"] = {}

    # Load Gobby hooks from template
    try:
        with open(source_hooks_template) as f:
            gobby_hooks_str = f.read()
    except OSError as e:
        logger.error(f"Failed to read hooks template: {e}")
        result["error"] = f"Failed to read hooks template: {e}"
        return result

    # Replace $HOOKS_DIR with absolute hooks directory path
    gobby_hooks_str = gobby_hooks_str.replace("$HOOKS_DIR", str(hooks_dir.resolve()))

    try:
        gobby_hooks = json.loads(gobby_hooks_str)
    except json.JSONDecodeError as e:
        logger.error(f"Failed to parse hooks template: {e}")
        result["error"] = f"Failed to parse hooks template: {e}"
        return result

    # Merge Gobby hooks
    new_hooks = gobby_hooks.get("hooks", {})
    for hook_type, hook_config in new_hooks.items():
        existing_hooks["hooks"][hook_type] = hook_config
        hooks_installed.append(hook_type)

    # Write merged hooks back using atomic write
    try:
        fd, temp_path = tempfile.mkstemp(dir=str(windsurf_path), suffix=".tmp", prefix="hooks_")
        try:
            with os.fdopen(fd, "w") as f:
                json.dump(existing_hooks, f, indent=2)
                f.flush()
                os.fsync(f.fileno())
            # Atomic replace
            os.replace(temp_path, hooks_file)
        except Exception:
            if os.path.exists(temp_path):
                os.unlink(temp_path)
            raise
    except OSError as e:
        logger.error(f"Failed to write hooks.json: {e}")
        if backup_file and backup_file.exists():
            try:
                copy2(backup_file, hooks_file)
                logger.info("Restored hooks.json from backup after write failure")
            except OSError as restore_error:
                logger.error(f"Failed to restore from backup: {restore_error}")
        result["error"] = f"Failed to write hooks.json: {e}"
        return result

    # Configure terminal tab title so tmux set-titles propagates to IDE
    terminal_result = configure_ide_terminal_title("Windsurf")
    result["terminal_configured"] = terminal_result.get("added", False)

    result["success"] = True
    return result


def uninstall_windsurf(project_path: Path, mode: str = "project") -> dict[str, Any]:
    """Uninstall Gobby integration from Windsurf.

    Args:
        project_path: Path to the project root
        mode: "global" removes from ~/.codeium/windsurf/hooks.json.
            "project" removes from {project}/.windsurf/hooks.json (existing behavior).

    Returns:
        Dict with uninstallation results
    """
    result: dict[str, Any] = {
        "success": False,
        "hooks_removed": [],
        "files_removed": [],
        "error": None,
    }

    if mode == "global":
        windsurf_path = Path.home() / ".codeium" / "windsurf"
        hooks_dir = Path(os.environ.get("GOBBY_HOOKS_DIR", str(Path.home() / ".gobby" / "hooks")))
    else:
        windsurf_path = project_path / ".windsurf"
        hooks_dir = windsurf_path / "hooks"
    hooks_file = windsurf_path / "hooks.json"

    # Remove hook dispatcher (only in project mode — global dispatcher is shared)
    if mode != "global":
        dispatcher = hooks_dir / "hook_dispatcher.py"
        if dispatcher.exists():
            try:
                dispatcher.unlink()
                result["files_removed"].append(str(dispatcher))
            except OSError as e:
                logger.warning(f"Failed to remove {dispatcher}: {e}")

    # Remove hooks from hooks.json
    if hooks_file.exists():
        try:
            with open(hooks_file) as f:
                hooks_config = json.load(f)

            # Remove all Gobby hooks (those that reference hook_dispatcher.py)
            if "hooks" in hooks_config:
                hooks_to_remove = []
                for hook_type, hook_list in hooks_config["hooks"].items():
                    if isinstance(hook_list, list):
                        for hook in hook_list:
                            cmd = hook.get("command", "")
                            if "hook_dispatcher.py" in cmd:
                                hooks_to_remove.append(hook_type)
                                break

                for hook_type in hooks_to_remove:
                    del hooks_config["hooks"][hook_type]
                    result["hooks_removed"].append(hook_type)

                # Write back
                with open(hooks_file, "w") as f:
                    json.dump(hooks_config, f, indent=2)

        except (json.JSONDecodeError, OSError) as e:
            logger.warning(f"Failed to update hooks.json: {e}")

    result["success"] = True
    return result
