#!/usr/bin/env python3
"""Aceternity MCP CLI - Powerful command-line interface.

Provides update, repair, post-install, and management commands.
"""

from __future__ import annotations

import json
import os
import shutil
import subprocess
import sys
from datetime import datetime
from pathlib import Path
from typing import Any

from .install import (
    Colors,
    check_prerequisites,
    configure_all_clients,
    expand_path,
    find_config_file,
    print_error,
    print_header,
    print_info,
    print_section,
    print_success,
    print_warning,
    run_command,
    verify_installation,
)


# ============================================================================
# Version Management
# ============================================================================
def get_current_version() -> str:
    """Get the current installed version."""
    try:
        from importlib.metadata import version

        return version("aceternity-mcp")
    except Exception:
        try:
            from . import __version__

            return __version__
        except Exception:
            return "unknown"


def get_latest_version() -> str | None:
    """Get the latest version from PyPI."""
    try:
        import urllib.request

        req = urllib.request.Request(
            "https://pypi.org/pypi/aceternity-mcp/json",
            headers={"User-Agent": "aceternity-mcp-cli"},
        )
        with urllib.request.urlopen(req, timeout=5) as response:
            data = json.loads(response.read())
            return data.get("info", {}).get("version")
    except Exception:
        return None


def check_for_updates() -> dict[str, Any]:
    """Check if updates are available."""
    current = get_current_version()
    latest = get_latest_version()

    if latest is None:
        return {"current": current, "latest": None, "available": False}

    current_parts = [int(x) for x in current.split(".") if x.isdigit()]
    latest_parts = [int(x) for x in latest.split(".") if x.isdigit()]

    has_update = latest_parts > current_parts

    return {
        "current": current,
        "latest": latest,
        "available": has_update,
    }


def perform_update(interactive: bool = True) -> bool:
    """Update the aceternity-mcp package."""
    print_section("Updating Aceternity MCP")

    update_info = check_for_updates()
    print_info(f"Current version: {update_info['current']}")

    if not update_info["available"]:
        if update_info["latest"]:
            print_success(f"Already on latest version ({update_info['latest']})")
            return True
        else:
            print_warning("Could not check for updates")
            print_info("Attempting upgrade anyway...")

    if update_info["available"]:
        print_info(f"Latest version: {update_info['latest']}")

    if interactive and not sys.stdin.isatty():
        interactive = False

    if interactive:
        response = (
            input(f"\nUpdate to {update_info['latest']}? [Y/n]: ").strip().lower()
        )
        if response in ("n", "no"):
            print_info("Update cancelled")
            return False

    print_info("Running pip install --upgrade aceternity-mcp...")

    success, output = run_command(
        [sys.executable, "-m", "pip", "install", "--upgrade", "aceternity-mcp"]
    )

    if success:
        print_success("Update completed successfully!")
        print_info("Please restart your AI tools to apply the update.")
        return True
    else:
        print_error(f"Update failed: {output}")
        print_info("Try running: pip install --upgrade aceternity-mcp")
        return False


# ============================================================================
# Repair Functionality
# ============================================================================
class RepairManager:
    """Manages repair operations for common issues."""

    def __init__(self) -> None:
        self.issues_found: list[dict[str, Any]] = []
        self.issues_fixed: list[dict[str, Any]] = []
        self.home = Path.home()

    def check_registry(self) -> dict[str, Any]:
        """Check if registry is present and valid."""
        result = {"name": "Registry", "status": "unknown", "details": ""}

        try:
            import aceternity_mcp
            from aceternity_mcp.registry import _find_registry_dir

            registry_path = _find_registry_dir()

            index_file = registry_path / "index.json"
            if not index_file.exists():
                result["status"] = "missing"
                result["details"] = "index.json not found"
                return result

            with open(index_file, "r", encoding="utf-8") as f:
                data = json.load(f)

            if "components" not in data or len(data["components"]) == 0:
                result["status"] = "empty"
                result["details"] = "Registry appears empty"
                return result

            result["status"] = "ok"
            result["details"] = f"Found {len(data['components'])} components"
        except Exception as e:
            result["status"] = "error"
            result["details"] = str(e)

        return result

    def check_mcp_command(self) -> dict[str, Any]:
        """Check if aceternity-mcp command is accessible."""
        result = {"name": "MCP Command", "status": "unknown", "details": ""}

        success, output = run_command(["aceternity-mcp", "--help"])

        if success:
            result["status"] = "ok"
            result["details"] = "Command accessible"
        else:
            result["status"] = "missing"
            result["details"] = f"Command not found: {output}"

        return result

    def check_client_configs(self) -> list[dict[str, Any]]:
        """Check MCP client configurations."""
        from .install import SUPPORTED_CLIENTS

        results = []

        for client_name, client_info in SUPPORTED_CLIENTS.items():
            result = {
                "name": client_info["name"],
                "status": "unknown",
                "details": "",
                "config_path": None,
            }

            config_path = find_config_file(client_info["config_paths"])
            if config_path:
                result["config_path"] = str(config_path)
                if config_path.exists():
                    try:
                        with open(config_path, "r", encoding="utf-8") as f:
                            config = json.load(f)

                        config_key = client_info["config_key"]
                        if config_key in config:
                            server_name = (
                                "aceternity_ui"
                                if config_key == "mcp_servers"
                                else "aceternity-ui"
                            )
                            if server_name in config[config_key]:
                                result["status"] = "ok"
                                result["details"] = "Configured correctly"
                            else:
                                result["status"] = "missing_config"
                                result["details"] = "Aceternity MCP not in config"
                        else:
                            result["status"] = "missing_config"
                            result["details"] = f"Missing '{config_key}' key"
                    except Exception as e:
                        result["status"] = "error"
                        result["details"] = f"Cannot read config: {e}"
                else:
                    result["status"] = "not_found"
                    result["details"] = "Config file doesn't exist"
            else:
                result["status"] = "not_found"
                result["details"] = "Could not locate config path"

            results.append(result)

        return results

    def check_python_path(self) -> dict[str, Any]:
        """Check if Python is on PATH."""
        result = {"name": "Python", "status": "unknown", "details": ""}

        python_exec = shutil.which(sys.executable)
        if python_exec:
            result["status"] = "ok"
            result["details"] = f"Found at: {python_exec}"
        else:
            result["status"] = "missing"
            result["details"] = "Python executable not on PATH"

        return result

    def diagnose(self) -> dict[str, Any]:
        """Run full diagnostic check."""
        return {
            "registry": self.check_registry(),
            "mcp_command": self.check_mcp_command(),
            "python": self.check_python_path(),
            "client_configs": self.check_client_configs(),
            "timestamp": datetime.now().isoformat(),
        }

    def repair_registry(self) -> bool:
        """Repair registry by re-syncing."""
        print_info("Syncing registry from Aceternity UI...")

        script_locations = [
            Path(__file__).parent.parent.parent / "scripts" / "sync_registry.py",
            Path(__file__).parent / "scripts" / "sync_registry.py",
        ]

        sync_script = None
        for loc in script_locations:
            if loc.exists():
                sync_script = loc
                break

        if not sync_script:
            print_error("Cannot find sync_registry.py script")
            return False

        success, output = run_command([sys.executable, str(sync_script)])

        if success:
            print_success("Registry synced successfully")
            return True
        else:
            print_error(f"Sync failed: {output}")
            return False

    def repair_client_config(self, client_name: str) -> bool:
        """Repair a specific client configuration."""
        from .install import SUPPORTED_CLIENTS

        if client_name not in SUPPORTED_CLIENTS:
            print_error(f"Unknown client: {client_name}")
            return False

        print_info(
            f"Repairing {SUPPORTED_CLIENTS[client_name]['name']} configuration..."
        )

        success = configure_all_clients()[client_name]

        if success:
            print_success(f"{SUPPORTED_CLIENTS[client_name]['name']} repaired")
            return True
        else:
            print_error(f"Failed to repair {SUPPORTED_CLIENTS[client_name]['name']}")
            return False

    def repair_all_configs(self) -> dict[str, bool]:
        """Repair all client configurations."""
        print_info("Repairing all client configurations...")
        return configure_all_clients()

    def fix_permissions(self) -> bool:
        """Fix common permission issues."""
        print_info("Checking file permissions...")

        try:
            import aceternity_mcp

            pkg_path = Path(aceternity_mcp.__file__).parent

            for py_file in pkg_path.glob("*.py"):
                if not os.access(py_file, os.R_OK):
                    os.chmod(py_file, 0o644)
                    print_info(f"Fixed read permissions on {py_file.name}")

            print_success("Permissions verified")
            return True
        except Exception as e:
            print_error(f"Permission fix failed: {e}")
            return False

    def run_repairs(
        self, repair_type: str = "all", interactive: bool = True
    ) -> dict[str, Any]:
        """Run repair operations."""
        print_section("Running Repairs")

        results: dict[str, Any] = {
            "diagnosis": self.diagnose(),
            "repairs_attempted": [],
            "repairs_successful": [],
            "repairs_failed": [],
        }

        if repair_type in ("all", "registry"):
            results["repairs_attempted"].append("registry")
            if self.repair_registry():
                results["repairs_successful"].append("registry")
            else:
                results["repairs_failed"].append("registry")

        if repair_type in ("all", "configs"):
            results["repairs_attempted"].append("configs")
            repair_results = self.repair_all_configs()
            for client, success in repair_results.items():
                if success:
                    results["repairs_successful"].append(f"config:{client}")
                else:
                    results["repairs_failed"].append(f"config:{client}")

        if repair_type in ("all", "permissions"):
            results["repairs_attempted"].append("permissions")
            if self.fix_permissions():
                results["repairs_successful"].append("permissions")
            else:
                results["repairs_failed"].append("permissions")

        return results


# ============================================================================
# Post-Install Wizard
# ============================================================================
def post_install_wizard(interactive: bool = True) -> int:
    """Run post-installation setup wizard."""
    print_header(
        "Aceternity MCP - Post-Install Setup", "Let's get everything configured"
    )

    if not interactive or not sys.stdin.isatty():
        print_info("Running in non-interactive mode...")
        return run_non_interactive_setup()

    print("\nWelcome! This wizard will help you configure Aceternity MCP.")
    print("Press Ctrl+C at any time to cancel.\n")

    # Step 1: Check prerequisites
    print_section("Step 1: Checking Prerequisites")
    prereqs = check_prerequisites()

    if not all(prereqs.values()):
        print_warning("Some prerequisites are missing.")
        if interactive:
            response = input("\nContinue anyway? [y/N]: ").strip().lower()
            if response not in ("y", "yes"):
                print_info("Setup cancelled")
                return 1

    # Step 2: Sync registry
    print_section("Step 2: Syncing Component Registry")
    from .install import get_api_key, sync_registry

    api_key = get_api_key()
    if not sync_registry(api_key):
        print_warning("Registry sync failed (can retry later)")

    # Step 3: Configure AI tools
    print_section("Step 3: Configuring AI Tools")
    from .install import select_clients

    selected = select_clients()

    if selected:
        results = configure_all_clients()
        for client_name in selected:
            if results.get(client_name):
                print_success(f"{client_name} configured")
            else:
                print_warning(f"{client_name} configuration skipped")
    else:
        print_info("Skipping client configuration")

    # Step 4: Verify installation
    print_section("Step 4: Verifying Installation")
    if verify_installation():
        print_success("Installation verified successfully!")
    else:
        print_warning(
            "Verification failed (you can run 'aceternity-mcp repair' to fix)"
        )

    # Step 5: Show next steps
    print_section("You're All Set!")
    print("\nTry these example prompts with your AI assistant:\n")
    print("  • 'Show me subtle background effects for landing pages'")
    print("  • 'Recommend a navbar + hero combination for a SaaS site'")
    print("  • 'Install Spotlight component and show dependencies'")
    print("  • 'What components work well for dark mode dashboards?'")
    print("\nUseful commands:\n")
    print("  aceternity-mcp update     - Check for and install updates")
    print("  aceternity-mcp repair     - Fix common issues")
    print("  aceternity-mcp status     - Check installation health")
    print("  aceternity-mcp install    - Re-run this setup wizard")
    print()

    return 0


def run_non_interactive_setup() -> int:
    """Run setup in non-interactive mode."""
    from .install import sync_registry

    print_info("Syncing registry...")
    sync_registry()

    print_info("Configuring all clients...")
    configure_all_clients()

    print_info("Verifying installation...")
    if verify_installation():
        print_success("Setup completed successfully!")
        return 0
    else:
        print_warning("Setup completed with warnings")
        return 1


# ============================================================================
# Status Command
# ============================================================================
def show_status(verbose: bool = False) -> None:
    """Show current installation status and health."""
    print_header("Aceternity MCP Status")

    # Version info
    update_info = check_for_updates()
    print_section("Version Information")
    print_info(f"Current version: {update_info['current']}")
    if update_info["latest"]:
        if update_info["available"]:
            print_warning(f"Update available: {update_info['latest']}")
            print_info("Run: aceternity-mcp update")
        else:
            print_success(f"Latest version: {update_info['latest']}")
    else:
        print_info("Could not check for updates")

    # System info
    print_section("System Information")
    print_info(f"Platform: {sys.platform}")
    print_info(
        f"Python: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
    )
    print_info(f"Python executable: {sys.executable}")

    # Health checks
    print_section("Health Checks")
    manager = RepairManager()
    diagnosis = manager.diagnose()

    # Registry status
    registry = diagnosis["registry"]
    if registry["status"] == "ok":
        print_success(f"Registry: {registry['details']}")
    else:
        print_error(f"Registry: {registry['details']}")

    # MCP command status
    mcp_cmd = diagnosis["mcp_command"]
    if mcp_cmd["status"] == "ok":
        print_success(f"MCP Command: {mcp_cmd['details']}")
    else:
        print_error(f"MCP Command: {mcp_cmd['details']}")

    # Python status
    python = diagnosis["python"]
    if python["status"] == "ok":
        print_success(f"Python: {python['details']}")
    else:
        print_error(f"Python: {python['details']}")

    # Client configs
    if verbose:
        print_section("Client Configurations")
        for config in diagnosis["client_configs"]:
            status_icon = (
                "✓"
                if config["status"] == "ok"
                else "⚠"
                if config["status"] in ("not_found", "missing_config")
                else "✗"
            )
            print_info(f"{status_icon} {config['name']}: {config['details']}")
            if config.get("config_path"):
                print_info(f"  Path: {config['config_path']}")

    print()


# ============================================================================
# Main CLI Entry Point
# ============================================================================
def main() -> int:
    """Main CLI entry point."""
    if len(sys.argv) < 2:
        print_help()
        return 0

    command = sys.argv[1].lower()
    args = sys.argv[2:]

    # Parse flags
    interactive = "--non-interactive" not in args and "-y" not in args
    verbose = "--verbose" in args or "-v" in args

    if command in ("update", "upgrade", "up"):
        return 0 if perform_update(interactive) else 1

    elif command in ("repair", "fix"):
        print_header("Aceternity MCP Repair Tool")

        repair_type = "all"
        for arg in args:
            if arg in ("--registry", "-r"):
                repair_type = "registry"
            elif arg in ("--configs", "-c"):
                repair_type = "configs"
            elif arg in ("--permissions", "-p"):
                repair_type = "permissions"

        manager = RepairManager()
        results = manager.run_repairs(repair_type, interactive)

        print("\n" + "=" * 60)
        print("Repair Summary")
        print("=" * 60)

        if results["repairs_successful"]:
            print_success(f"Successful: {', '.join(results['repairs_successful'])}")

        if results["repairs_failed"]:
            print_error(f"Failed: {', '.join(results['repairs_failed'])}")
            print_info("\nTry running with --verbose for more details")
            print_info(
                "Or report the issue at: https://github.com/devinoldenburg/aceternity-mcp/issues"
            )

        return 0 if not results["repairs_failed"] else 1

    elif command in ("install", "setup", "init", "post-install"):
        return post_install_wizard(interactive)

    elif command in ("status", "info", "health"):
        show_status(verbose)
        return 0

    elif command in ("diagnose", "check"):
        print_header("Aceternity MCP Diagnostics")
        manager = RepairManager()
        diagnosis = manager.diagnose()
        print(json.dumps(diagnosis, indent=2))
        return 0

    elif command in ("--version", "-v", "version"):
        print(get_current_version())
        return 0

    elif command in ("--help", "-h", "help"):
        print_help()
        return 0

    else:
        print_error(f"Unknown command: {command}")
        print_info("Run 'aceternity-mcp --help' for available commands")
        return 1


def print_help() -> None:
    """Print help message."""
    print_header("Aceternity MCP CLI", "Powerful command-line interface")

    print("Available Commands:\n")

    commands = [
        ("install", "Run post-installation setup wizard", "aceternity-mcp install"),
        ("update", "Check for and install updates", "aceternity-mcp update"),
        ("repair", "Fix common installation issues", "aceternity-mcp repair"),
        ("status", "Show installation status and health", "aceternity-mcp status"),
        ("diagnose", "Run diagnostics and output JSON", "aceternity-mcp diagnose"),
        ("--version", "Show version information", "aceternity-mcp --version"),
        ("--help", "Show this help message", "aceternity-mcp --help"),
    ]

    for cmd, desc, example in commands:
        print(f"  {Colors.BOLD}{cmd:<15}{Colors.RESET} {desc}")
        print(f"  {Colors.DIM}Example: {example}{Colors.RESET}\n")

    print("Repair Options:\n")
    print("  --registry, -r     Repair registry only")
    print("  --configs, -c      Repair client configs only")
    print("  --permissions, -p  Fix file permissions only\n")

    print("Global Options:\n")
    print("  --verbose, -v      Show detailed output")
    print("  --non-interactive, -y  Run without prompts\n")

    print("=" * 60)
    print("Quick Start:\n")
    print("  1. First time? Run: aceternity-mcp install")
    print("  2. Having issues? Run: aceternity-mcp repair")
    print("  3. Want updates? Run: aceternity-mcp update")
    print("  4. Check status: aceternity-mcp status")
    print()


if __name__ == "__main__":
    sys.exit(main())
