"""Diagnostic checks: agent setup, copilot conflicts, completion test."""
from __future__ import annotations

import asyncio
import shutil
import subprocess
from typing import Any

import httpx

from proxym.api._diag_common import INTERNAL_PORT
from proxym.api._diag_proxy import check_llm_proxy
from proxym.api._diag_providers import check_providers_config
from proxym.api._diag_roo import check_roo_cline_config
from proxym.api._diag_vscode import CONFLICTING_EXTENSIONS
from proxym.config import get_settings
from proxym.providers import TaskTier, cheapest_model


def _find_conflicting_extensions(installed: list[str]) -> list[str]:
    installed_lower = {ext.lower() for ext in installed}
    return [ext for ext in CONFLICTING_EXTENSIONS if ext.lower() in installed_lower]


def _settings_mentions_copilot(settings_text: str) -> bool:
    return "copilot" in settings_text.lower()


async def check_copilot_conflict() -> dict[str, Any]:
    """Detect GitHub Copilot / Copilot Chat extension conflicts."""
    result = {
        "service": "copilot_conflict",
        "has_conflict": False,
        "conflicting_extensions": [],
        "recommendation": None,
        "details": {},
    }

    docker_bin = shutil.which("docker")
    if not docker_bin:
        result["details"]["skipped"] = "docker not on PATH"
        return result

    try:
        proc = await asyncio.to_thread(
            subprocess.run,
            ["docker", "exec", "proxym-vscode", "code-server", "--list-extensions"],
            capture_output=True, text=True, timeout=15,
        )
        if proc.returncode == 0:
            installed = [e.strip().lower() for e in proc.stdout.strip().splitlines()]
            conflicting = _find_conflicting_extensions(installed)
            if conflicting:
                result["has_conflict"] = True
                result["conflicting_extensions"].extend(conflicting)

        settings_proc = await asyncio.to_thread(
            subprocess.run,
            ["docker", "exec", "proxym-vscode",
             "cat", "/home/coder/.local/share/code-server/User/settings.json"],
            capture_output=True, text=True, timeout=10,
        )
        if settings_proc.returncode == 0:
            settings_text = settings_proc.stdout
            if _settings_mentions_copilot(settings_text):
                result["details"]["copilot_in_settings"] = True
                if not result["has_conflict"]:
                    result["has_conflict"] = True
                    result["details"]["reason"] = "copilot referenced in settings.json"

    except Exception as e:
        result["details"]["error"] = str(e)

    if result["has_conflict"]:
        result["recommendation"] = (
            "Uninstall GitHub Copilot extensions. They are not available in code-server "
            "(Open VSX) and conflict with Roo Code. Use Roo Code or Continue.dev instead. "
            "Error: 'The extension GitHub.copilot-chat cannot be installed because it was not found.'"
        )
    else:
        result["recommendation"] = "No Copilot conflicts detected. Roo Code is the primary AI assistant."

    return result


async def check_agent_setup(base_url: str) -> dict[str, Any]:
    """Comprehensive agent readiness check — config + connectivity + extension."""
    result = {
        "service": "agent_setup",
        "ready": False,
        "checks": [],
        "details": {},
    }

    checks = []

    # 1. Check settings.json exists and has Roo Code config
    roo_config = await check_roo_cline_config()
    checks.append({
        "name": "settings.json exists",
        "pass": roo_config["settings_file_exists"],
        "detail": "Roo Code settings file found" if roo_config["settings_file_exists"]
                  else "settings.json not found — run entrypoint.sh or restart VS Code container",
    })
    checks.append({
        "name": "Roo Code API configured",
        "pass": roo_config["configured"],
        "detail": f"Provider: {roo_config['api_provider']}, URL: {roo_config['base_url']}"
                  if roo_config["configured"]
                  else "Roo Code not configured — check roo-cline.apiProvider and roo-cline.openAiBaseUrl",
    })
    checks.append({
        "name": "API key set",
        "pass": roo_config.get("details", {}).get("has_api_key", False),
        "detail": "API key present" if roo_config.get("details", {}).get("has_api_key")
                  else "No API key — set PROXYM_API_KEY or AI_PROXY_MASTER_KEY in .env",
    })
    checks.append({
        "name": "Mode configs present",
        "pass": len(roo_config.get("details", {}).get("mode_configs", [])) >= 4,
        "detail": f"Modes: {', '.join(roo_config.get('details', {}).get('mode_configs', []))}"
                  if roo_config.get("details", {}).get("mode_configs")
                  else "Missing mode configs (code, architect, debug, ask)",
    })

    # 2. Check proxy reachable
    proxy_status = await check_llm_proxy(base_url=base_url)
    checks.append({
        "name": "LLM proxy reachable",
        "pass": proxy_status["reachable"],
        "detail": f"{proxy_status['models_available']} models available"
                  if proxy_status["reachable"]
                  else f"Cannot reach proxy: {proxy_status.get('details', {}).get('error', 'unknown')}",
    })

    # 3. Check at least one provider has a key
    providers = await check_providers_config()
    has_provider = any(p["has_key"] or p["is_local"] for p in providers["providers"])
    checks.append({
        "name": "LLM provider available",
        "pass": has_provider,
        "detail": f"{providers['total_providers']} providers configured"
                  if has_provider
                  else "No LLM providers configured — add API keys to .env",
    })

    # 4. Check no Copilot conflict
    copilot = await check_copilot_conflict()
    checks.append({
        "name": "No Copilot conflicts",
        "pass": not copilot["has_conflict"],
        "detail": copilot["recommendation"],
    })

    result["checks"] = checks
    result["ready"] = all(c["pass"] for c in checks)
    result["details"]["total_checks"] = len(checks)
    result["details"]["passed"] = sum(1 for c in checks if c["pass"])
    result["details"]["failed"] = sum(1 for c in checks if not c["pass"])

    return result


async def test_agent_completion() -> dict[str, Any]:
    """Test a simple completion through the proxy to verify agent functionality."""
    settings = get_settings()
    proxy_url = f"http://127.0.0.1:{INTERNAL_PORT}"
    api_key = settings.master_key

    result = {
        "service": "agent_test",
        "test_type": "simple_completion",
        "success": False,
        "response_time_ms": 0,
        "details": {},
    }

    if not settings.available_providers():
        result["details"]["skipped"] = "No LLM providers configured"
        return result

    available_provider_names = set(settings.available_providers().keys())
    model_spec = cheapest_model(TaskTier.TRIVIAL, available_providers=available_provider_names)
    if model_spec is None:
        result["details"]["skipped"] = "No trivial-tier model available for agent test"
        return result

    try:
        import time
        start = time.time()

        async with httpx.AsyncClient(timeout=30.0) as client:
            headers = {
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json",
            }

            test_model = model_spec.id

            payload = {
                "model": test_model,
                "messages": [
                    {"role": "system", "content": "You are a helpful assistant. Reply with only: OK"},
                    {"role": "user", "content": "Say OK"}
                ],
                "max_tokens": 10,
            }

            response = await client.post(
                f"{proxy_url}/v1/chat/completions",
                headers=headers,
                json=payload
            )

            result["response_time_ms"] = round((time.time() - start) * 1000, 2)

            if response.status_code == 200:
                data = response.json()
                content = data.get("choices", [{}])[0].get("message", {}).get("content", "")
                result["success"] = "OK" in content.upper() or len(content) > 0
                result["details"]["response"] = content[:100]
                result["details"]["model_used"] = data.get("model")
                result["details"]["requested_model"] = test_model
            else:
                result["details"]["error"] = f"HTTP {response.status_code}: {response.text[:200]}"

    except Exception as e:
        result["details"]["error"] = str(e)

    return result
