"""
fw_doctor/runner.py — Orchestrates all diagnostic checks and formats output.

Runs each check INDEPENDENTLY (KV₇), collects results, and renders a
color-coded terminal report.  Exit code: 0 = all pass/warn, 1 = any fail.

Structural pattern: Multiplicative gate (AX52) — a single FAIL in any
check means the whole gate collapses.  The runner makes this visible.
"""

from __future__ import annotations

import sys
import time
from typing import List, Optional, TextIO

from .checks import ALL_CHECKS, CheckResult, CheckStatus


# ── ANSI colors (Windows 10+ supports these in conhost/WT) ──────────

_RESET = "\033[0m"
_BOLD = "\033[1m"
_GREEN = "\033[92m"
_YELLOW = "\033[93m"
_RED = "\033[91m"
_CYAN = "\033[96m"
_DIM = "\033[2m"


def _status_badge(status: CheckStatus) -> str:
    """Return a colored badge for terminal output."""
    if status == CheckStatus.PASS:
        return f"{_GREEN}✓ PASS{_RESET}"
    elif status == CheckStatus.WARN:
        return f"{_YELLOW}⚠ WARN{_RESET}"
    elif status == CheckStatus.FAIL:
        return f"{_RED}✗ FAIL{_RESET}"
    else:
        return f"{_DIM}○ SKIP{_RESET}"


def _enable_windows_ansi() -> None:
    """Enable ANSI escape codes on Windows console."""
    try:
        import ctypes
        kernel32 = ctypes.windll.kernel32  # type: ignore[attr-defined]
        # STD_OUTPUT_HANDLE = -11
        handle = kernel32.GetStdHandle(-11)
        mode = ctypes.c_ulong()
        kernel32.GetConsoleMode(handle, ctypes.byref(mode))
        # ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
        kernel32.SetConsoleMode(handle, mode.value | 0x0004)
    except Exception:
        pass  # Not critical — worst case: raw escape codes in output


# ── Runner ───────────────────────────────────────────────────────────

def run_all(
    *,
    verbose: bool = False,
    stream: Optional[TextIO] = None,
    no_color: bool = False,
) -> List[CheckResult]:
    """Run every registered check and print a formatted report.

    Parameters
    ----------
    verbose : bool
        If True, print detail dicts for each check.
    stream : TextIO | None
        Output stream (default: sys.stdout).
    no_color : bool
        If True, suppress ANSI colors.

    Returns
    -------
    list[CheckResult]
        Results from all checks.
    """
    out = stream or sys.stdout

    if sys.platform == "win32" and not no_color:
        _enable_windows_ansi()

    # Strip colors if requested
    if no_color:
        global _RESET, _BOLD, _GREEN, _YELLOW, _RED, _CYAN, _DIM
        _RESET = _BOLD = _GREEN = _YELLOW = _RED = _CYAN = _DIM = ""

    # Header
    out.write(f"\n{_BOLD}{_CYAN}╔═══════════════════════════════════╗{_RESET}\n")
    out.write(f"{_BOLD}{_CYAN}║    dusun framework · fw_doctor    ║{_RESET}\n")
    out.write(f"{_BOLD}{_CYAN}╚═══════════════════════════════════╝{_RESET}\n\n")

    results: List[CheckResult] = []
    t_total = time.perf_counter()

    for check_fn in ALL_CHECKS:
        # Each check is independent (KV₇) — no shared state
        result = check_fn()
        results.append(result)

        badge = _status_badge(result.status)
        timing = f"{_DIM}{result.elapsed_ms:7.1f}ms{_RESET}"
        out.write(f"  {badge}  {timing}  {result.name}: {result.message}\n")

        if verbose and result.detail:
            for k, v in result.detail.items():
                out.write(f"           {_DIM}{k}: {v}{_RESET}\n")

    total_ms = (time.perf_counter() - t_total) * 1000

    # Summary
    n_pass = sum(1 for r in results if r.status == CheckStatus.PASS)
    n_warn = sum(1 for r in results if r.status == CheckStatus.WARN)
    n_fail = sum(1 for r in results if r.status == CheckStatus.FAIL)
    n_skip = sum(1 for r in results if r.status == CheckStatus.SKIP)

    out.write(f"\n{_BOLD}{'─' * 50}{_RESET}\n")
    parts = [f"{_GREEN}{n_pass} pass{_RESET}"]
    if n_warn:
        parts.append(f"{_YELLOW}{n_warn} warn{_RESET}")
    if n_fail:
        parts.append(f"{_RED}{n_fail} fail{_RESET}")
    if n_skip:
        parts.append(f"{_DIM}{n_skip} skip{_RESET}")

    out.write(f"  {' · '.join(parts)}  {_DIM}({total_ms:.0f}ms){_RESET}\n")

    # Gate result (AX52)
    if n_fail > 0:
        out.write(f"\n  {_RED}{_BOLD}GATE: FAIL{_RESET}  "
                   f"{_DIM}(AX52 — zero coverage in ≥1 dimension){_RESET}\n\n")
    elif n_warn > 0:
        out.write(f"\n  {_YELLOW}{_BOLD}GATE: WARN{_RESET}  "
                   f"{_DIM}(all dimensions active, some constraints soft-violated){_RESET}\n\n")
    else:
        out.write(f"\n  {_GREEN}{_BOLD}GATE: PASS{_RESET}  "
                   f"{_DIM}(all dimensions operational){_RESET}\n\n")

    return results


def exit_code(results: List[CheckResult]) -> int:
    """Return 0 if no FAILs, else 1."""
    return 1 if any(r.status == CheckStatus.FAIL for r in results) else 0
