"""Offline environment checks for the Janus Labs CLI."""

from __future__ import annotations

from dataclasses import dataclass
from importlib import metadata
import os
import shutil
import subprocess
import sys


@dataclass(frozen=True)
class DoctorCheck:
    name: str
    status: str
    detail: str


def _format_python_version(version_info: object) -> str:
    parts = list(version_info[:3]) if hasattr(version_info, "__getitem__") else []
    while len(parts) < 3:
        parts.append(0)
    return ".".join(str(part) for part in parts[:3])


def check_python_version() -> DoctorCheck:
    version_info = sys.version_info
    version_tuple = tuple(version_info[:2])
    version_text = _format_python_version(version_info)
    if version_tuple >= (3, 12):
        return DoctorCheck("Python 3.12+", "ok", f"Found {version_text}")
    return DoctorCheck("Python 3.12+", "fail", f"Found {version_text}; requires 3.12+")


def check_package(name: str) -> DoctorCheck:
    try:
        version = metadata.version(name)
    except metadata.PackageNotFoundError:
        return DoctorCheck(
            f"Package: {name}",
            "fail",
            f"Missing; install with: pip install {name}",
        )
    return DoctorCheck(f"Package: {name}", "ok", f"Found {version}")


def check_optional_package(name: str, purpose: str) -> DoctorCheck:
    try:
        version = metadata.version(name)
    except metadata.PackageNotFoundError:
        return DoctorCheck(
            f"Optional package: {name}",
            "warn",
            f"Missing; needed for {purpose}",
        )
    return DoctorCheck(f"Optional package: {name}", "ok", f"Found {version}")


def check_git() -> DoctorCheck:
    git_path = shutil.which("git")
    if not git_path:
        return DoctorCheck("Git", "fail", "Missing from PATH")

    result = subprocess.run(
        [git_path, "--version"],
        capture_output=True,
        text=True,
        check=False,
    )
    output = (result.stdout or result.stderr or "").strip()
    if result.returncode == 0:
        return DoctorCheck("Git", "ok", output or f"Found at {git_path}")
    return DoctorCheck("Git", "fail", output or "Installed but not runnable")


def check_agent_cli(name: str) -> DoctorCheck:
    agent_path = shutil.which(name)
    if not agent_path:
        return DoctorCheck(f"Agent CLI: {name}", "warn", "Missing from PATH")
    return DoctorCheck(f"Agent CLI: {name}", "ok", f"Found at {agent_path}")


def check_api_key(env_var: str, purpose: str) -> DoctorCheck:
    if os.environ.get(env_var):
        return DoctorCheck(f"Env: {env_var}", "ok", f"Set for {purpose}")
    return DoctorCheck(f"Env: {env_var}", "warn", f"Missing; needed for {purpose}")


def run_doctor() -> list[DoctorCheck]:
    checks = [check_python_version()]

    for package_name in ("pytest", "gitpython", "pydantic", "pyyaml", "httpx"):
        checks.append(check_package(package_name))

    checks.append(check_optional_package("deepeval", "--judge"))
    checks.append(check_optional_package("questionary", "interactive menu"))
    checks.append(check_git())

    for agent_name in ("codex", "gemini", "copilot", "claude"):
        checks.append(check_agent_cli(agent_name))

    checks.append(check_api_key("OPENAI_API_KEY", "--judge"))
    checks.append(check_api_key("CI_UPLOAD_TOKEN", "baseline uploads (CI only)"))
    return checks


def format_doctor_table(checks: list[DoctorCheck]) -> str:
    name_width = max(len("Check"), *(len(check.name) for check in checks))
    status_width = max(len("Status"), *(len(check.status) for check in checks))

    lines = [
        f"{'Check':<{name_width}}  {'Status':<{status_width}}  Detail",
        f"{'-' * name_width}  {'-' * status_width}  {'-' * len('Detail')}",
    ]

    for check in checks:
        lines.append(
            f"{check.name:<{name_width}}  {check.status:<{status_width}}  {check.detail}"
        )

    ok_count = sum(check.status == "ok" for check in checks)
    warn_count = sum(check.status == "warn" for check in checks)
    fail_count = sum(check.status == "fail" for check in checks)
    lines.append("")
    lines.append(f"Result: {ok_count} ok, {warn_count} warn, {fail_count} fail")
    return "\n".join(lines)


def cmd_doctor(args) -> int:
    del args
    checks = run_doctor()
    print("Janus Labs Doctor")
    print("=================")
    print()
    print(format_doctor_table(checks))
    return 1 if any(check.status == "fail" for check in checks) else 0
