"""
Smart setup command for KuzuMemory.

Combines initialization and installation into a single intelligent command
that auto-detects existing installations and updates them as needed.
"""

import sys
from pathlib import Path

import click

from ..installers.claude_hooks import ClaudeHooksInstaller
from ..utils.project_setup import find_project_root, get_project_db_path, get_project_memories_dir
from ..utils.subservient import get_subservient_config, is_subservient_mode
from .cli_utils import rich_panel, rich_print
from .init_commands import init
from .install_unified import AVAILABLE_INTEGRATIONS, _detect_installed_systems


def _show_version_info() -> None:
    """
    Display current version and upgrade instructions.

    Provides manual upgrade commands for different installation methods.
    """
    from ..__version__ import __version__

    rich_print(f"\n📦 Current version: {__version__}", style="cyan")
    rich_print("\n💡 To upgrade to the latest version:", style="dim")
    rich_print("   pip install --upgrade kuzu-memory", style="dim")
    rich_print("   # or with uv:", style="dim")
    rich_print("   uv pip install --upgrade kuzu-memory", style="dim")


@click.command()
@click.option(
    "--skip-install",
    is_flag=True,
    help="Skip AI tool installation (init only)",
)
@click.option(
    "--integration",
    type=click.Choice(
        [
            "claude-code",
            "claude-desktop",
            "codex",
            "cursor",
            "vscode",
            "windsurf",
            "auggie",
        ],
        case_sensitive=False,
    ),
    help="Specific integration to install (auto-detects if not specified)",
)
@click.option(
    "--force",
    is_flag=True,
    help="Force reinstall even if already configured",
)
@click.option(
    "--dry-run",
    is_flag=True,
    help="Preview changes without modifying files",
)
@click.option(
    "--skip-git-hooks",
    is_flag=True,
    help="Skip git post-commit hooks installation (auto-installs when git repo detected)",
)
@click.pass_context
def setup(
    ctx: click.Context,
    skip_install: bool,
    integration: str | None,
    force: bool,
    dry_run: bool,
    skip_git_hooks: bool,
) -> None:
    """
    🚀 Smart setup - Initialize and configure KuzuMemory (RECOMMENDED).

    This is the ONE command to get KuzuMemory ready in your project.
    It intelligently handles both new setups and updates to existing installations.

    \b
    🎯 WHAT IT DOES:
      1. Detects project root automatically
      2. Initializes memory database (if needed)
      3. Auto-detects installed AI tools
      4. Installs/updates integrations intelligently
      5. Auto-installs Claude Code hooks and MCP
      6. Auto-installs git hooks (when git repo detected)
      7. Verifies everything is working

    \b
    🚀 EXAMPLES:
      # Smart setup (recommended - auto-detects everything)
      kuzu-memory setup

      # Setup without git hooks
      kuzu-memory setup --skip-git-hooks

      # Setup for specific integration without git hooks
      kuzu-memory setup --integration claude-code --skip-git-hooks

      # Initialize only (skip AI tool installation)
      kuzu-memory setup --skip-install

      # Force reinstall everything
      kuzu-memory setup --force

      # Preview what would happen
      kuzu-memory setup --dry-run

    \b
    💡 TIP:
      For most users, just run 'kuzu-memory setup' with no arguments.
      It will install git hooks and Claude Code hooks automatically.

    \b
    ⚙️  ADVANCED USAGE:
      If you need granular control, you can still use:
      • kuzu-memory init                # Just initialize
      • kuzu-memory install <tool>      # Just install integration
      • kuzu-memory git install-hooks   # Just install git hooks
    """
    try:
        # ═══════════════════════════════════════════════════════════
        # PHASE 1: PROJECT DETECTION & INITIALIZATION
        # ═══════════════════════════════════════════════════════════

        # Show version info if not in dry-run mode
        if not dry_run:
            _show_version_info()

        rich_panel(
            "Smart Setup - Automated KuzuMemory Configuration\n\n"
            "This will:\n"
            "✅ Initialize memory database\n"
            "✅ Detect installed AI tools\n"
            "✅ Configure integrations\n"
            "✅ Install Claude Code hooks and MCP\n"
            "✅ Install git hooks (if git repo detected)\n"
            "✅ Verify setup\n\n"
            f"Mode: {'DRY RUN (preview only)' if dry_run else 'LIVE SETUP'}",
            title="🚀 KuzuMemory Setup",
            style="cyan",
        )

        # Detect project root
        try:
            project_root_raw = ctx.obj.get("project_root")
            if project_root_raw is None:
                project_root_raw = find_project_root()

            # Ensure project_root is a Path object for type safety
            if isinstance(project_root_raw, str):
                project_root = Path(project_root_raw)
            elif isinstance(project_root_raw, Path):
                project_root = project_root_raw
            else:
                # Should not happen, but handle gracefully
                raise ValueError(f"Unexpected project_root type: {type(project_root_raw)}")

            rich_print(f"\n📁 Project detected: {project_root}", style="green")
        except Exception as e:
            rich_print(
                f"\n❌ Could not detect project root: {e}\n"
                "   Please run this command from within a project directory.",
                style="red",
            )
            sys.exit(1)

        memories_dir = get_project_memories_dir(project_root)
        # Honour the global --db-path flag when set; otherwise derive from project root.
        db_path = ctx.obj.get("db_path") or get_project_db_path(project_root)

        # Check initialization status — three distinct states:
        #   1. fully initialized: db_path exists (happy path)
        #   2. partial init: memories_dir exists but db_path does not
        #      (e.g. a previous interrupted setup created the directory but
        #       kuzu never wrote the database file)
        #   3. not initialized: neither exists
        already_initialized = db_path.exists()
        partial_init = memories_dir.exists() and not already_initialized

        if already_initialized:
            rich_print(f"✅ Memory database already initialized: {db_path}", style="dim")
            if force:
                rich_print("   Force flag set - will reinitialize", style="yellow")
        elif partial_init:
            rich_print(
                f"⚠️  Memory directory exists but database is missing: {memories_dir}",
                style="yellow",
            )
            rich_print("   Will reinitialize database in existing directory...")
        else:
            rich_print(f"📦 Memory database not found - will create: {db_path}")

        # Initialize or update database
        if not already_initialized or force:
            if dry_run:
                rich_print("\n[DRY RUN] Would initialize memory database at:", style="yellow")
                rich_print(f"  {db_path}", style="dim")
            else:
                rich_print("\n⚙️  Initializing memory database...", style="cyan")
                # Force init when in partial-init state so init doesn't skip
                # the directory-creation step that would otherwise fail silently.
                init_force = force or partial_init
                try:
                    # Explicitly pass None for Path-typed options to avoid Sentinel error
                    ctx.invoke(init, force=init_force, config_path=None, project_root=None)
                except SystemExit as _init_exit:
                    # init command exited with non-zero; show a useful hint instead
                    # of the former misleading "Database already exists" message.
                    if _init_exit.code != 0:
                        if partial_init:
                            rich_print(
                                "   ⚠️  Database initialization failed for the existing "
                                f"directory {memories_dir}.",
                                style="yellow",
                            )
                            rich_print(
                                "      Run: kuzu-memory init --force   to recreate the database.",
                                style="dim",
                            )
                        else:
                            rich_print(
                                "   ⚠️  Database initialization failed.",
                                style="yellow",
                            )

        # Verify database schema and optimization for both new and existing databases
        if not dry_run and db_path.exists():
            rich_print("\n🔧 Verifying database optimization...", style="cyan")
            try:
                from ..storage.schema import ensure_indexes

                verification_results = ensure_indexes(db_path)

                if verification_results.get("schema_valid", False):
                    rich_print("  ✅ Schema verified and optimized", style="green")
                else:
                    rich_print("  ⚠️  Schema verification failed", style="yellow")

            except Exception as e:
                # Verification failure is non-critical, log warning
                rich_print(f"  ⚠️  Optimization verification skipped: {e}", style="yellow")

        # ═══════════════════════════════════════════════════════════
        # PHASE 2: AI TOOL DETECTION & INSTALLATION
        # ═══════════════════════════════════════════════════════════

        # Check for subservient mode before installation
        if is_subservient_mode(project_root):
            config = get_subservient_config(project_root)
            managed_by = (
                config.get("managed_by", "parent framework") if config else "parent framework"
            )
            rich_print(
                f"\n📦 Subservient mode detected - hooks managed by {managed_by}",
                style="cyan",
            )
            rich_print("   Skipping hook installation (managed externally)", style="dim")
            skip_install = True  # Force skip

        if skip_install:
            rich_print("\n⏭️  Skipping AI tool installation (--skip-install)", style="yellow")
        else:
            rich_print("\n🔍 Detecting installed AI tools...", style="cyan")

            # Detect what's already installed
            installed_systems = _detect_installed_systems(project_root)

            if installed_systems:
                rich_print(
                    f"   Found {len(installed_systems)} existing installation(s)",
                    style="green",
                )
                for system in installed_systems:
                    status_icon = (
                        "✅"
                        if system.health_status == "healthy"
                        else "⚠️"
                        if system.health_status == "needs_repair"
                        else "❌"
                    )
                    rich_print(f"   {status_icon} {system.name}: {system.health_status}")

                if integration:
                    # User explicitly requested a specific integration — update only that one
                    needs_update = any(
                        s.health_status == "needs_repair" or force
                        for s in installed_systems
                        if s.name == integration
                    )
                    if needs_update or force:
                        action = "Reinstalling" if force else "Updating"
                        if dry_run:
                            rich_print(
                                f"\n[DRY RUN] Would {action.lower()} integration: {integration}",
                                style="yellow",
                            )
                        else:
                            rich_print(
                                f"\n⚙️  {action} {integration} integration...",
                                style="cyan",
                            )
                            _install_integration(ctx, integration, project_root, force=True)
                    else:
                        rich_print(
                            f"\n✅ {integration} integration is up to date",
                            style="green",
                        )
                else:
                    # No specific integration requested — update ALL detected ones
                    healthy_list = [
                        s for s in installed_systems if s.health_status == "healthy" and not force
                    ]
                    needs_update_list = [
                        s
                        for s in installed_systems
                        if s.health_status in ("needs_repair", "broken") or force
                    ]

                    for s in healthy_list:
                        rich_print(f"\n✅ {s.name} integration is up to date", style="green")

                    for s in needs_update_list:
                        action = "Reinstalling" if force else "Updating"
                        if dry_run:
                            rich_print(
                                f"\n[DRY RUN] Would {action.lower()} integration: {s.name}",
                                style="yellow",
                            )
                        else:
                            rich_print(
                                f"\n⚙️  {action} {s.name} integration...",
                                style="cyan",
                            )
                            _install_integration(ctx, s.name, project_root, force=True)

            else:
                # No existing installations — auto-detect and install to all available platforms
                rich_print(
                    "   No existing installations found — running auto-detection...",
                    style="yellow",
                )

                if integration:
                    # User specified a particular integration — install only that one
                    if dry_run:
                        rich_print(
                            f"\n[DRY RUN] Would install: {integration}",
                            style="yellow",
                        )
                    else:
                        rich_print(
                            f"\n⚙️  Installing {integration} integration...",
                            style="cyan",
                        )
                        _install_integration(ctx, integration, project_root, force=force)
                else:
                    # Fully autonomous: detect every present platform and install to each
                    if dry_run:
                        rich_print(
                            "\n[DRY RUN] Would auto-detect and install to all available platforms",
                            style="yellow",
                        )
                    else:
                        auto_results = _auto_detect_and_install_all_platforms(
                            project_root, force=force, dry_run=False
                        )

                        if auto_results:
                            successful = [(n, m) for n, ok, m in auto_results if ok]
                            failed = [(n, m) for n, ok, m in auto_results if not ok]

                            if successful:
                                rich_print(
                                    f"\n✅ Installed to {len(successful)} platform(s):",
                                    style="green",
                                )
                                for name, msg in successful:
                                    rich_print(f"   ✅ {name}: {msg}", style="green")
                            if failed:
                                rich_print(
                                    f"\n⚠️  Failed for {len(failed)} platform(s):",
                                    style="yellow",
                                )
                                for name, msg in failed:
                                    rich_print(f"   ❌ {name}: {msg}", style="yellow")
                        else:
                            # Truly nothing detected — show targeted guidance
                            rich_print(
                                "\n💡 No AI tool platforms detected automatically.",
                                style="cyan",
                            )
                            rich_print("\n  📋 Install manually with:")
                            rich_print("     kuzu-memory setup --integration claude-code")
                            rich_print("     kuzu-memory setup --integration cursor")
                            rich_print("     kuzu-memory setup --integration windsurf")
                            rich_print("     kuzu-memory setup --integration codex")
                            rich_print("     kuzu-memory setup --integration auggie")

        # ═══════════════════════════════════════════════════════════
        # PHASE 2.25: CLAUDE CODE HOOKS & MCP INSTALLATION
        # ═══════════════════════════════════════════════════════════

        claude_hooks_installed = False
        if not skip_install:
            if dry_run:
                rich_print(
                    "\n[DRY RUN] Would install Claude Code hooks and MCP",
                    style="yellow",
                )
            else:
                rich_print("\n🪝 Installing Claude Code hooks and MCP...", style="cyan")
                try:
                    hooks_installer = ClaudeHooksInstaller(project_root)
                    # Always update hooks on setup - no force flag needed
                    hooks_result = hooks_installer.install(force=True, dry_run=dry_run)
                    if hooks_result.success:
                        rich_print("  ✅ Claude Code hooks and MCP configured", style="green")
                        claude_hooks_installed = True
                    else:
                        rich_print(
                            f"  ⚠️ Claude Code hooks: {hooks_result.message}",
                            style="yellow",
                        )
                except Exception as e:
                    rich_print(
                        f"  ⚠️ Claude Code hooks installation failed: {e}",
                        style="yellow",
                    )
                    rich_print(
                        "    You can install manually: kuzu-memory install claude-code",
                        style="dim",
                    )

        # ═══════════════════════════════════════════════════════════
        # PHASE 2.5: GIT HOOKS INSTALLATION
        # ═══════════════════════════════════════════════════════════

        git_hooks_installed = False
        git_repo_detected = _detect_git_repository(project_root)

        if git_repo_detected and not skip_git_hooks:
            if dry_run:
                rich_print(
                    "\n[DRY RUN] Would install git hooks for auto-sync",
                    style="yellow",
                )
            else:
                rich_print("\n🪝 Installing git hooks...", style="cyan")
                # Always update git hooks on setup - no force flag needed
                git_hooks_installed = _install_git_hooks(ctx, project_root, force=True)
        elif not git_repo_detected and not skip_git_hooks:
            rich_print(
                "\n⚠️  Git repository not detected - skipping git hooks installation",
                style="yellow",
            )

        # ═══════════════════════════════════════════════════════════
        # PHASE 2.75: VERIFY HOOKS INSTALLATION
        # ═══════════════════════════════════════════════════════════

        if not skip_install and not dry_run:
            # Verify hooks were installed correctly
            rich_print("\n🔍 Verifying hooks installation...", style="cyan")

            try:
                from ..services import ConfigService
                from .async_utils import run_async
                from .service_manager import ServiceManager

                config_service = ConfigService(project_root)
                config_service.initialize()

                with ServiceManager.diagnostic_service(config_service) as diagnostic:
                    hooks_status = run_async(diagnostic.check_hooks_status(project_root))

                    overall = hooks_status["overall_status"]
                    if overall == "fully_configured":
                        rich_print("  ✅ All hooks verified successfully", style="green")
                    elif overall == "partially_configured":
                        rich_print("  ⚠️  Hooks partially configured", style="yellow")

                        # Show what's missing
                        if not hooks_status["git_hooks"]["installed"] and git_repo_detected:
                            rich_print(
                                "    - Git hooks: Not installed (use --with-git-hooks)",
                                style="dim",
                            )
                        if not hooks_status["claude_code_hooks"]["installed"]:
                            rich_print("    - Claude Code hooks: Not configured", style="dim")
                    else:
                        rich_print("  ⚠️  Hooks verification failed", style="yellow")

                config_service.cleanup()

            except Exception as e:
                rich_print(f"  ⚠️  Hooks verification skipped: {e}", style="dim")

        # ═══════════════════════════════════════════════════════════
        # PHASE 3: VERIFICATION & COMPLETION
        # ═══════════════════════════════════════════════════════════

        if dry_run:
            rich_panel(
                "Dry Run Complete - No Changes Made\n\n"
                "The above shows what would happen with a real setup.\n"
                "Remove --dry-run to perform actual setup.",
                title="✅ Preview Complete",
                style="green",
            )
        else:
            # Build completion message
            next_steps = []

            if skip_install:
                next_steps.append("• Install AI tool: kuzu-memory install <integration>")

            # Add hooks status to next steps
            if git_hooks_installed:
                next_steps.append("✅ Git hooks installed - commits will auto-sync to memory")
            elif not skip_git_hooks and git_repo_detected:
                next_steps.append("💡 Note: Git hooks installation attempted - check status above")
            elif skip_git_hooks and git_repo_detected:
                next_steps.append("💡 Enable auto-sync: kuzu-memory git install-hooks")

            if claude_hooks_installed:
                next_steps.append("✅ Claude Code hooks configured - ready to use")

            next_steps.extend(
                [
                    "• Store your first memory: kuzu-memory memory store 'Important info'",
                    "• View status: kuzu-memory status",
                    "• Get help: kuzu-memory help",
                ]
            )

            # Determine hooks status messages
            if git_hooks_installed:
                git_hooks_status = "✅ Installed"
            elif skip_git_hooks:
                git_hooks_status = "⏭️  Skipped (--skip-git-hooks)"
            elif not git_repo_detected:
                git_hooks_status = "⚠️  Not installed (no git repo)"
            else:
                git_hooks_status = "❌ Not installed"

            if claude_hooks_installed:
                claude_hooks_status = "✅ Installed"
            elif skip_install:
                claude_hooks_status = "⏭️  Skipped (--skip-install)"
            else:
                claude_hooks_status = "❌ Not installed"

            rich_panel(
                "Setup Complete! 🎉\n\n"
                f"📁 Project: {project_root}\n"
                f"🗄️  Database: {db_path}\n"
                f"📂 Memories: {memories_dir}\n"
                f"🪝 Git Hooks: {git_hooks_status}\n"
                f"🤖 Claude Code Hooks: {claude_hooks_status}\n\n"
                "Next steps:\n" + "\n".join(next_steps),
                title="✅ KuzuMemory Ready",
                style="green",
            )

    except Exception as e:
        if ctx.obj.get("debug"):
            raise
        rich_print(f"\n❌ Setup failed: {e}", style="red")
        rich_print(
            "\n💡 Try running with --debug for more details:\n   kuzu-memory --debug setup",
            style="dim",
        )
        sys.exit(1)


def _auto_detect_and_install_all_platforms(
    project_root: Path,
    force: bool = False,
    dry_run: bool = False,
) -> list[tuple[str, bool, str]]:
    """
    Auto-detect all installed AI platforms and install kuzu-memory MCP to each.

    When py-mcp-installer is available, iterates over every platform in PLATFORM_MAP
    and attempts installation wherever confidence >= 0.3 or the platform config
    directory already exists.  Falls back to AISystemDetector when py-mcp-installer
    is unavailable, installing via the registry-based path for any platform whose
    parent directory exists (can_install=True).

    Args:
        project_root: Root directory of the project.
        force: Force reinstall even if already configured.
        dry_run: Preview changes without modifying files.

    Returns:
        List of (platform_name, success, message) tuples for every attempted install.
    """
    from ..installers.mcp_installer_adapter import (
        HAS_MCP_INSTALLER,
        PLATFORM_MAP,
        MCPInstallerAdapter,
    )

    results: list[tuple[str, bool, str]] = []

    if HAS_MCP_INSTALLER:
        # Use py-mcp-installer to probe each known platform
        for platform_enum, platform_name in PLATFORM_MAP.items():
            try:
                adapter = MCPInstallerAdapter(
                    project_root=project_root,
                    platform=platform_enum,
                    dry_run=dry_run,
                )
                info = adapter.installer.platform_info
                confidence: float = getattr(info, "confidence", 0.0)
                config_path = getattr(info, "config_path", None)
                cli_available: bool = getattr(info, "cli_available", False)

                # Decide whether this platform is present enough to attempt install
                config_dir_exists = config_path is not None and Path(config_path).parent.exists()
                should_install = confidence >= 0.3 or cli_available or config_dir_exists

                if not should_install:
                    continue

                if dry_run:
                    results.append(
                        (
                            platform_name,
                            True,
                            f"[DRY RUN] would install to {platform_name}",
                        )
                    )
                    continue

                result = adapter.install(force=force)
                results.append((platform_name, result.success, result.message))

            except Exception as exc:
                # A failure for one platform must not block others
                results.append((platform_name, False, str(exc)))

    else:
        # Fallback: use AISystemDetector + registry-based installers
        from ..installers.detection import AISystemDetector
        from ..installers.registry import get_installer

        detector = AISystemDetector(project_root)
        available = detector.detect_available()

        for detected in available:
            name = detected.installer_name
            # Only attempt platforms that the registry knows about
            if name not in AVAILABLE_INTEGRATIONS:
                continue
            try:
                installer = get_installer(name, project_root)
                if installer is None:
                    continue

                if dry_run:
                    results.append((name, True, f"[DRY RUN] would install to {name}"))
                    continue

                result = installer.install(force=force)
                results.append((name, result.success, result.message))

            except Exception as exc:
                results.append((name, False, str(exc)))

    return results


def _install_integration(
    ctx: click.Context, integration_name: str, project_root: Path, force: bool = False
) -> None:
    """
    Install or update an AI tool integration.

    Args:
        ctx: Click context
        integration_name: Name of integration to install
        project_root: Project root directory
        force: Force reinstall
    """
    from .install_unified import install_command

    try:
        # Forward to install command with appropriate flags
        ctx.invoke(
            install_command,
            integration=integration_name,
            project_root=None,
            force=force,
            dry_run=False,
            verbose=False,
        )
    except SystemExit as e:
        # install_command called sys.exit(); treat non-zero as a warning so
        # the overall setup continues rather than aborting.
        if e.code != 0:
            rich_print(
                "⚠️  Integration installation did not complete successfully.",
                style="yellow",
            )
            rich_print(
                f"   You can retry later with: kuzu-memory install {integration_name}",
                style="dim",
            )
    except Exception as e:
        rich_print(f"⚠️  Installation warning: {e}", style="yellow")
        rich_print("   You can manually install later with:", style="dim")
        rich_print(f"   kuzu-memory install {integration_name}", style="dim")


def _detect_git_repository(project_root: Path) -> bool:
    """
    Check if project_root is in a git repository.

    Searches up to 5 parent directories for .git directory.

    Args:
        project_root: Project root directory to start search

    Returns:
        True if git repository detected, False otherwise
    """
    current = project_root
    for _ in range(5):
        if (current / ".git").exists():
            return True
        if current == current.parent:
            break
        current = current.parent
    return False


def _find_git_directory(project_root: Path) -> Path | None:
    """
    Find .git directory by searching up directory tree.

    Searches up to 5 parent directories for .git directory.

    Args:
        project_root: Project root directory to start search

    Returns:
        Path to .git directory if found, None otherwise
    """
    current = project_root
    for _ in range(5):
        git_dir = current / ".git"
        if git_dir.exists():
            return git_dir
        if current == current.parent:
            break
        current = current.parent
    return None


def _install_git_hooks(ctx: click.Context, project_root: Path, force: bool = False) -> bool:
    """
    Install git post-commit hooks for automatic sync.

    Delegates to the existing git install-hooks command.

    Args:
        ctx: Click context
        project_root: Project root directory
        force: Force overwrite existing hooks

    Returns:
        True if hooks installed successfully, False otherwise
    """
    try:
        # Delegate to git install-hooks command
        from .git_commands import install_hooks as git_install_hooks_cmd

        ctx.invoke(git_install_hooks_cmd, force=force)
        rich_print("✅ Git hooks installed successfully", style="green")
        return True

    except SystemExit as e:
        if e.code != 0:
            rich_print("⚠️  Git hooks installation failed", style="yellow")
            rich_print(
                "   You can install manually: kuzu-memory git install-hooks",
                style="dim",
            )
        return False

    except Exception as e:
        rich_print(f"⚠️  Git hooks warning: {e}", style="yellow")
        rich_print(
            "   You can install manually: kuzu-memory git install-hooks",
            style="dim",
        )
        return False


__all__ = ["setup"]
