"""Production-readiness checks for local Maeris CLI + MCP setup."""

from __future__ import annotations

import json
import os
import shutil
import stat
import subprocess
import sys
from pathlib import Path

import click

from maeris_mcp.auth.token_store import TokenStore

from ._core import cli
from ._utils import _repo_config_dir


def _status(ok: bool, label: str, detail: str) -> bool:
    icon = "✓" if ok else "✗"
    color = "green" if ok else "red"
    click.secho(f"  {icon} {label}", fg=color, nl=False)
    click.echo(f"  {detail}")
    return ok


def _warn(label: str, detail: str) -> None:
    click.secho(f"  ! {label}", fg="yellow", nl=False)
    click.echo(f"  {detail}")


def _fix(msg: str) -> None:
    click.secho(f"    → {msg}", fg="cyan")


@cli.command("doctor")
def doctor_cmd() -> None:
    """Validate local CLI/MCP setup and highlight production blockers.

    \b
    Checks:
      • Python version (3.10+)
      • maeris binary on PATH
      • Claude CLI availability
      • Playwright installation
      • .mcp.json configuration
      • Credential storage and file permissions
      • Backend reachability
      • Environment variable configuration
    """
    issues = 0
    warnings = 0

    click.echo()
    click.secho("Maeris doctor", bold=True)
    click.echo()

    # ------------------------------------------------------------------ #
    # Python version
    # ------------------------------------------------------------------ #
    py_ok = sys.version_info >= (3, 10)
    if not _status(py_ok, "Python", f"{sys.version.split()[0]}"):
        _fix("Upgrade to Python 3.10+: https://python.org/downloads")
        issues += 1

    # ------------------------------------------------------------------ #
    # maeris binary itself
    # ------------------------------------------------------------------ #
    maeris_bin = shutil.which("maeris")
    if maeris_bin:
        _status(True, "maeris binary", f"found at {maeris_bin}")
    else:
        _status(False, "maeris binary", "not found on PATH")
        _fix("pip install maeris")
        if sys.platform == "win32":
            _fix("If still not found, add Python Scripts to PATH:")
            import site as _site
            scripts = _site.getusersitepackages().replace("site-packages", "Scripts")
            _fix(f"  Add to PATH:  {scripts}")
            _fix("  Settings → System → Advanced → Environment Variables → Path → Edit")
        elif sys.platform == "darwin":
            _fix("If still not found, your shell may not include pip's bin directory.")
            _fix("  Add to ~/.zshrc:  export PATH=\"$HOME/.local/bin:$PATH\"")
            _fix("  Then run:         source ~/.zshrc")
        else:
            _fix("If still not found:")
            _fix("  Add to ~/.bashrc:  export PATH=\"$HOME/.local/bin:$PATH\"")
            _fix("  Then run:          source ~/.bashrc")
        _fix("Or use pipx (handles PATH automatically):  pipx install maeris")
        issues += 1

    # ------------------------------------------------------------------ #
    # Claude CLI (required for scan/test generation)
    # ------------------------------------------------------------------ #
    claude_bin = shutil.which("claude")
    if claude_bin:
        _status(True, "Claude CLI", f"found at {claude_bin}")
    else:
        _warn("Claude CLI", "not found on PATH — scan and test generation commands will be unavailable")
        _fix("Install Claude Code: https://claude.ai/download")
        warnings += 1

    # ------------------------------------------------------------------ #
    # Playwright (required for baseline generate and run_and_fix_tests)
    # ------------------------------------------------------------------ #
    pw_check = subprocess.run(
        [sys.executable, "-c", "import playwright; import playwright.sync_api"],
        capture_output=True,
    )
    if pw_check.returncode == 0:
        # Also verify browser binaries are installed
        browser_check = subprocess.run(
            [sys.executable, "-m", "playwright", "install", "--dry-run", "chromium"],
            capture_output=True,
            text=True,
        )
        browsers_ok = browser_check.returncode == 0 or "already installed" in (browser_check.stdout + browser_check.stderr).lower()
        if browsers_ok:
            _status(True, "Playwright", "installed with browser binaries")
        else:
            _warn("Playwright", "installed but browser binaries may be missing")
            _fix("python -m playwright install chromium")
            warnings += 1
    else:
        _status(False, "Playwright", "not installed — baseline generate and run_and_fix_tests will fail")
        _fix("pip install playwright && python -m playwright install chromium")
        issues += 1

    # ------------------------------------------------------------------ #
    # .mcp.json repo config
    # ------------------------------------------------------------------ #
    mcp_path = Path.cwd() / ".mcp.json"
    if not mcp_path.exists():
        _warn(".mcp.json", "missing — MCP tools not registered for this repo")
        _fix("Run: maeris app init")
        warnings += 1
    else:
        try:
            data = json.loads(mcp_path.read_text())
            servers = (data or {}).get("mcpServers") or {}
            maeris_cfg = servers.get("maeris") or {}
            cmd = maeris_cfg.get("command")
            args = maeris_cfg.get("args") or []
            ok = cmd == "maeris" and isinstance(args, list) and args[:1] == ["serve"]
            if not _status(ok, ".mcp.json", "mcpServers.maeris → `maeris serve`"):
                _fix("Re-run: maeris app init")
                issues += 1
            else:
                # Verify MAERIS_CONFIG_DIR is set in the entry
                cfg_dir_set = bool((maeris_cfg.get("env") or {}).get("MAERIS_CONFIG_DIR"))
                if not cfg_dir_set:
                    _warn(".mcp.json", "MAERIS_CONFIG_DIR not set in env — credentials may not load")
                    _fix("Re-run: maeris app init")
                    warnings += 1
        except Exception as exc:
            _status(False, ".mcp.json", f"invalid JSON: {exc}")
            _fix("Re-run: maeris app init")
            issues += 1

    # ------------------------------------------------------------------ #
    # Auth + credential storage
    # ------------------------------------------------------------------ #
    config_dir = _repo_config_dir()
    token_store = TokenStore(config_dir=config_dir)
    cred_file = token_store.credentials_file
    if not cred_file.exists():
        _warn("Credentials", f"not found for this repo ({cred_file})")
        _fix("Run: maeris auth login")
        warnings += 1
    else:
        try:
            mode = stat.S_IMODE(cred_file.stat().st_mode)
            perm_ok = mode == 0o600
            if not _status(perm_ok, "Credentials", f"{cred_file}  (mode {oct(mode)})"):
                _fix(f"Fix permissions: chmod 600 {cred_file}")
                issues += 1
            else:
                # Check if token is expired
                if token_store.is_token_expired():
                    _warn("Auth token", "expired")
                    _fix("Run: maeris auth login")
                    warnings += 1
                else:
                    email = token_store.get_email() or ""
                    app = token_store.get_app_name() or token_store.get_app_id() or "no app linked"
                    _status(True, "Auth token", f"valid  ({email}  app: {app})")
        except Exception as exc:
            _status(False, "Credentials", f"could not read: {exc}")
            issues += 1

    # ------------------------------------------------------------------ #
    # Backend reachability (non-blocking: only a warning)
    # ------------------------------------------------------------------ #
    import urllib.request
    import urllib.error

    from maeris_mcp.config import ENV as _ENV
    api_url = os.getenv("MAERIS_API_URL", _ENV.service_url)
    health_url = api_url.rstrip("/") + "/health"
    try:
        req = urllib.request.Request(health_url, method="GET")
        with urllib.request.urlopen(req, timeout=5):
            _status(True, "Backend", "reachable")
    except urllib.error.HTTPError:
        # Any HTTP response (even 404) means the server is up
        _status(True, "Backend", "reachable")
    except Exception as exc:
        _warn("Backend", f"not reachable: {exc}")
        _fix("Check your internet connection.")
        warnings += 1

    # ------------------------------------------------------------------ #
    # Endpoint configuration
    # ------------------------------------------------------------------ #
    app_url_env = os.getenv("MAERIS_APP_URL", "").strip()
    api_url_env = os.getenv("MAERIS_API_URL", "").strip()
    if app_url_env:
        _status(True, "MAERIS_APP_URL", app_url_env)
        if "-dev." in app_url_env or "railway.app" in app_url_env:
            _warn("MAERIS_APP_URL", "looks like a non-production endpoint — verify before release")
            warnings += 1
    else:
        _warn("MAERIS_APP_URL", "not set (using built-in default)")
        warnings += 1
    if api_url_env:
        _status(True, "MAERIS_API_URL", api_url_env)
        if "-dev." in api_url_env or "railway.app" in api_url_env:
            _warn("MAERIS_API_URL", "looks like a non-production endpoint — verify before release")
            warnings += 1
    else:
        _warn("MAERIS_API_URL", "not set (using built-in default)")
        warnings += 1

    # ------------------------------------------------------------------ #
    # Summary
    # ------------------------------------------------------------------ #
    click.echo()
    if issues:
        click.secho(
            f"Doctor: {issues} error(s), {warnings} warning(s). Fix errors before using Maeris.",
            fg="red",
            bold=True,
        )
        sys.exit(1)
    elif warnings:
        click.secho(
            f"Doctor: 0 errors, {warnings} warning(s). Some optional features may be unavailable.",
            fg="yellow",
            bold=True,
        )
    else:
        click.secho("Doctor: all checks passed.", fg="green", bold=True)

