"""Diagnostic checks: VS Code Web reachability + extensions."""
from __future__ import annotations

import asyncio
import shutil
import subprocess
from typing import Any

from proxym.api._diag_common import _probe_first_ok
from proxym.config import get_settings

# Extensions that MUST be installed for full functionality
_REQUIRED_EXTENSIONS = [
    "rooveterinary.roo-cline",
    "continue.continue",
    "ms-python.python",
    "charliermarsh.ruff",
]

# Extensions available from Open VSX (code-server marketplace)
_OPEN_VSX_EXTENSIONS = [
    "continue.continue",
    "ms-python.python",
    "charliermarsh.ruff",
    "eamodio.gitlens",
    "mhutchie.git-graph",
    "humao.rest-client",
    "redhat.vscode-yaml",
    "tamasfe.even-better-toml",
    "mikestead.dotenv",
    "usernamehw.errorlens",
    "pkief.material-icon-theme",
]

# Extensions NOT in Open VSX — need manual .vsix install
_VSIX_ONLY = [
    "rooveterinary.roo-cline",
]

# Extensions that conflict with proxym setup
CONFLICTING_EXTENSIONS = [
    "github.copilot",
    "github.copilot-chat",
]


async def check_vscode_status() -> dict[str, Any]:
    """Check if VS Code Web is running and accessible."""
    settings = get_settings()
    internal_candidates = [
        f"http://proxym-vscode:{settings.vscode_port}",
        f"http://vscode:{settings.vscode_port}",
    ]
    public_candidates = [
        f"http://localhost:{settings.vscode_port}",
        f"http://127.0.0.1:{settings.vscode_port}",
    ]
    vscode_url = internal_candidates[0]
    public_url = public_candidates[0]

    result = {
        "service": "vscode",
        "url": public_url,
        "internal_url": vscode_url,
        "reachable": False,
        "password_configured": bool(settings.vscode_password),
        "password": settings.vscode_password if settings.vscode_password else None,
        "details": {},
    }

    url, response, err = await _probe_first_ok(public_candidates + internal_candidates)
    if response is not None and url is not None:
        result["reachable"] = True
        result["url"] = url
        result["details"]["status_code"] = response.status_code
        result["details"]["has_login_form"] = (
            "password" in response.text.lower() or response.status_code in (401, 403)
        )
    else:
        result["details"]["error"] = err or "All connection attempts failed"

    return result


async def check_extensions() -> dict[str, Any]:
    """Check installed VS Code extensions via docker exec."""
    result = {
        "service": "extensions",
        "installed": [],
        "missing_required": [],
        "missing_vsix": [],
        "conflicting": [],
        "total_installed": 0,
        "details": {},
    }

    docker_bin = shutil.which("docker")
    if not docker_bin:
        result["details"]["error"] = "docker not found 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:
            result["details"]["error"] = f"docker exec failed: {proc.stderr.strip()}"
            return result

        installed = [e.strip().lower() for e in proc.stdout.strip().splitlines() if e.strip()]
        result["installed"] = installed
        result["total_installed"] = len(installed)

        # Check required (Open VSX)
        for ext in _OPEN_VSX_EXTENSIONS:
            if ext.lower() not in installed:
                result["missing_required"].append(ext)

        # Check VSIX-only (expected to be missing unless manually installed)
        for ext in _VSIX_ONLY:
            if ext.lower() not in installed:
                result["missing_vsix"].append(ext)

        # Check conflicting
        for ext in CONFLICTING_EXTENSIONS:
            if ext.lower() in installed:
                result["conflicting"].append(ext)

    except subprocess.TimeoutExpired:
        result["details"]["error"] = "docker exec timed out"
    except FileNotFoundError:
        result["details"]["error"] = "docker not available"
    except Exception as e:
        result["details"]["error"] = str(e)

    return result
