"""Tool health-check endpoint and diagnostic helpers."""

import sys
import shutil
from typing import Any

import structlog
from fastapi import APIRouter, Request

from proxym.tools import ToolRegistry

logger = structlog.get_logger()
router = APIRouter(tags=["tools"])


# ── Diagnostic helpers ────────────────────────────────────

from proxym.dashboard.tools.utils._aider_install_fix import _aider_install_fix


def _health_diag_base(tool, tool_providers: dict[str, str]) -> dict[str, Any]:
    return {
        "name": tool.name,
        "category": tool.category.value,
        "available": tool.is_available,
        "binary": tool.binary,
        "binary_found": bool(tool.binary and shutil.which(tool.binary)),
        "provider": tool_providers.get(tool.name, "openrouter"),
        "provider_configured": False,
        "api_key_present": False,
        "docker_instance": False,
        "kvm_instance": False,
        "vm_instance": False,
        "status": "unknown",
        "issues": [],
        "fixes": [],
    }


def _apply_provider_health(diag: dict[str, Any], configured_providers: dict[str, Any]) -> None:
    provider_name = diag["provider"]
    if diag["name"] == "human":
        diag["provider"] = "manual"
        diag["provider_configured"] = True
        diag["api_key_present"] = True
        return

    if provider_name in configured_providers:
        diag["provider_configured"] = True
        diag["api_key_present"] = True
        return

    if "openrouter" in configured_providers and provider_name != "ollama":
        diag["provider_configured"] = True
        diag["api_key_present"] = True
        diag["provider"] = f"{provider_name} (via openrouter)"
        return

    diag["issues"].append(f"Provider '{provider_name}' not configured — no API key")
    diag["fixes"].append({
        "action": "config",
        "label": f"Set {provider_name.upper()}_API_KEY",
        "command": f"export {provider_name.upper()}_API_KEY=<your-key>",
        "description": f"Add API key for {provider_name} in .env or environment",
    })


# ── Tool-specific install fix registry ─────────────────────

_BINARY_MISSING_FIXES: dict[str, callable] = {
    "aider": lambda tool: _aider_install_fix(),
    "claude-code": lambda tool: {
        "action": "install",
        "label": "Install claude-code",
        "command": "npm install -g @anthropic-ai/claude-code",
        "description": "Install Claude Code CLI tool",
    },
}

_DESKTOP_IDE_TOOLS = {"windsurf", "cursor"}

_DOCKER_REQUIRED_TOOLS: dict[str, tuple[str, str, str]] = {
    # tool_name -> (issue_msg, docker_profile, label)
    "vscode": ("Docker-backed VS Code container not running", "vscode", "Start VS Code container"),
    "roo-code": ("Docker-backed VS Code container not running", "vscode", "Start VS Code container"),
    "cline": ("Docker-backed VS Code container not running", "vscode", "Start VS Code container"),
    "browser": ("Open WebUI container not running", "webui", "Start Open WebUI"),
}


def _apply_runtime_health(diag: dict[str, Any], tool) -> None:
    if tool.name == "human":
        return

    # Binary missing — use registry or generic message
    if tool.binary and not diag["binary_found"]:
        if tool.name in _BINARY_MISSING_FIXES:
            diag["issues"].append(f"{tool.binary} binary not found on PATH")
            diag["fixes"].append(_BINARY_MISSING_FIXES[tool.name](tool))
        elif tool.name in _DESKTOP_IDE_TOOLS:
            diag["issues"].append(f"{tool.name} is a desktop IDE — not available in container")
            diag["fixes"].append({
                "action": "info",
                "label": f"{tool.name} runs on host only",
                "command": f"# Install from https://{tool.name}.com — dispatches via echo inside container",
                "description": "Desktop IDE tool — dispatch works but actual execution requires host",
            })

    # Detect available instances by kind
    for inst in tool.instances:
        kind_key = f"{inst.kind}_instance"
        if kind_key in diag and inst.is_available:
            diag[kind_key] = True
            break

    # Check for KVM/VM-based tools that need VM access
    has_vm_instance = any(inst.kind in ("kvm", "vm") for inst in tool.instances)
    if has_vm_instance and not (diag["kvm_instance"] or diag["vm_instance"]):
        vm_inst = next((i for i in tool.instances if i.kind in ("kvm", "vm")), None)
        if vm_inst:
            if vm_inst.vm_name:
                diag["issues"].append(f"KVM VM '{vm_inst.vm_name}' not running")
                diag["fixes"].append({
                    "action": "start_vm",
                    "label": f"Start {vm_inst.vm_name} VM",
                    "command": f"virsh start {vm_inst.vm_name}" if shutil.which("virsh") else f"# Start VM {vm_inst.vm_name} via your hypervisor",
                    "description": f"Start the KVM virtual machine '{vm_inst.vm_name}' for {tool.name}",
                })
            elif vm_inst.vm_host:
                diag["issues"].append(f"VM at {vm_inst.vm_host} not reachable via SSH")
                diag["fixes"].append({
                    "action": "info",
                    "label": "Check VM SSH access",
                    "command": f"# Ensure VM at {vm_inst.vm_host} is running and accessible via SSH",
                    "description": f"VM host {vm_inst.vm_host} not reachable. Check VM status and SSH connectivity.",
                })

    # Docker-required tools — registry-based
    if tool.name in _DOCKER_REQUIRED_TOOLS and not diag["docker_instance"]:
        issue_msg, profile, label = _DOCKER_REQUIRED_TOOLS[tool.name]
        diag["issues"].append(issue_msg)
        diag["fixes"].append({
            "action": "start_container",
            "label": label,
            "command": f"docker compose --profile {profile} up -d",
            "description": f"Start the container (profile: {profile}) used by {tool.name}",
        })


def _finalize_health_status(diag: dict[str, Any]) -> None:
    if not diag["issues"]:
        diag["status"] = "ok"
    elif diag["available"] or diag["provider_configured"]:
        diag["status"] = "degraded"
    else:
        diag["status"] = "unavailable"


# ── Endpoint ─────────────────────────────────────────────

@router.get("/readiness")
async def tools_readiness(request: Request) -> dict[str, Any]:
    """Return cached tool readiness snapshot from the startup orchestrator.

    This is fast (no re-probe) and reflects the last startup/periodic check.
    The orchestrator probes all tools at boot and every 120s, emitting SSE events.
    """
    orchestrator = getattr(request.app.state, "tool_orchestrator", None)
    if orchestrator is None:
        return {"error": "orchestrator not started", "tools": [], "summary": {}}
    return orchestrator.snapshot


@router.get("/healthcheck")
async def tools_healthcheck() -> dict[str, Any]:
    """Comprehensive health check for every registered tool.

    For each tool returns: binary available, provider configured,
    api key present, docker instance available, and actionable diagnosis.
    """
    from proxym.config import get_settings
    settings = get_settings()
    configured_providers = settings.available_providers()
    tool_providers = settings.tool_providers
    reg = ToolRegistry.get()

    results = []
    total_ok = 0
    total_degraded = 0
    total_unavailable = 0

    for tool in reg.list_tools():
        diag = _health_diag_base(tool, tool_providers)
        _apply_provider_health(diag, configured_providers)
        _apply_runtime_health(diag, tool)
        _finalize_health_status(diag)

        if diag["status"] == "ok":
            total_ok += 1
        elif diag["status"] == "degraded":
            total_degraded += 1
        else:
            total_unavailable += 1

        results.append(diag)

    return {
        "tools": results,
        "summary": {
            "total": len(results),
            "ok": total_ok,
            "degraded": total_degraded,
            "unavailable": total_unavailable,
        },
        "providers_configured": list(configured_providers.keys()),
        "tool_providers": tool_providers,
    }
