"""``tribunal doctor`` — check Tribunal installation health.

Prints ✓ / ✗ / ⚠ for each check with a fix suggestion for failures.
Returns exit code 1 if any check fails (useful for CI).
"""

from __future__ import annotations

import json
import socket
import sys
from pathlib import Path

_PLUGIN_DIR = Path.home() / ".claude" / "tribunal"

_CHECK = "✓"
_FAIL = "✗"
_WARN = "⚠"


def _check_settings_hooks() -> tuple[bool | None, str]:
    """Check ``.claude/settings.json`` has correct Tribunal hooks registered."""
    settings_path = Path(".claude") / "settings.json"
    if not settings_path.exists():
        return False, (
            "No .claude/settings.json found in current directory\n"
            "    Fix: Run 'tribunal init' to set up hooks for this project"
        )

    try:
        data = json.loads(settings_path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as exc:
        return False, (
            f"Cannot read .claude/settings.json: {exc}\n"
            "    Fix: Check file permissions and JSON syntax"
        )

    hooks = data.get("hooks", {})
    if not hooks:
        return False, (
            "No hooks registered in .claude/settings.json\n"
            "    Fix: Run 'tribunal repair' to register Tribunal hooks"
        )

    all_commands: list[str] = []
    for phase_hooks in hooks.values():
        for hook in phase_hooks if isinstance(phase_hooks, list) else []:
            all_commands.append(str(hook.get("command", "")))

    has_tribunal_hook = any(
        "tribunal" in cmd.lower() or "file_checker" in cmd or "tdd_enforcer" in cmd
        for cmd in all_commands
    )
    if not has_tribunal_hook:
        return False, (
            "No Tribunal hooks found in .claude/settings.json\n"
            "    Fix: Run 'tribunal repair' to register hooks"
        )

    return True, f"Hooks registered ({len(all_commands)} hook command(s) found)"


def _check_hooks_json() -> tuple[bool | None, str]:
    """Check ``tribunal/hooks/hooks.json`` exists and is valid JSON."""
    hooks_json = _PLUGIN_DIR / "hooks" / "hooks.json"
    if not hooks_json.exists():
        return False, (
            f"hooks.json not found at {hooks_json}\n"
            "    Fix: Run 'tribunal repair' to reinstall plugin files"
        )

    try:
        data = json.loads(hooks_json.read_text(encoding="utf-8"))
    except json.JSONDecodeError as exc:
        return False, (
            f"hooks.json is invalid JSON: {exc}\n"
            "    Fix: Run 'tribunal repair' to reinstall plugin files"
        )

    if not isinstance(data, (dict, list)):
        return False, "hooks.json is not a valid JSON object or array"

    return True, f"hooks.json is valid ({hooks_json})"


def _check_python_deps() -> tuple[bool | None, str]:
    """Check Python version and hook dependencies are available."""
    if sys.version_info < (3, 10):
        return False, (
            f"Python {sys.version_info[0]}.{sys.version_info[1]} detected; "
            "Tribunal requires Python 3.10+\n"
            "    Fix: Install Python 3.10 or newer"
        )

    hooks_dir = _PLUGIN_DIR / "hooks"
    if not hooks_dir.exists():
        return False, (
            f"Hooks directory not found: {hooks_dir}\n"
            "    Fix: Run 'tribunal repair' to reinstall"
        )

    py_ver = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
    return True, f"Python {py_ver}, hooks directory present"


def _check_worker_service() -> tuple[bool | None, str]:
    """Check whether the worker service is reachable on its configured port."""
    port = 41777  # default from SettingsDefaultsManager
    host = "127.0.0.1"

    # Try to read port/host from the worker settings file if available
    settings_file = Path.home() / ".tribunal" / "memory" / "settings.json"
    if settings_file.exists():
        try:
            data = json.loads(settings_file.read_text(encoding="utf-8"))
            port = int(data.get("TRIBUNAL_WORKER_PORT", data.get("SKILLFIELD_WORKER_PORT", port)))
            host = data.get("TRIBUNAL_WORKER_HOST", data.get("SKILLFIELD_WORKER_HOST", host))
        except (OSError, json.JSONDecodeError, ValueError):
            pass

    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(1.0)
        result = sock.connect_ex((host, port))
        sock.close()
        if result == 0:
            return True, f"Worker service reachable at {host}:{port}"
        else:
            return None, (
                f"Worker service not responding on {host}:{port}\n"
                "    Fix: Launch 'tribunal' once to start the worker service"
            )
    except Exception as exc:  # pragma: no cover
        return None, f"Could not probe worker service: {exc}"


_CHECKS: list[tuple[str, object]] = [
    ("Settings hooks", _check_settings_hooks),
    ("hooks.json", _check_hooks_json),
    ("Python & deps", _check_python_deps),
    ("Worker service", _check_worker_service),
]


def run_doctor(checks: list[tuple[str, object]] | None = None) -> int:
    """Run all doctor checks and return exit code.

    Args:
        checks: Override the default check list (useful in tests).

    Returns:
        0 if all checks passed (✓ or ⚠), 1 if any check failed (✗).
    """
    print("Tribunal Doctor — checking installation health\n")

    active_checks = checks if checks is not None else _CHECKS
    any_failed = False

    for name, check_fn in active_checks:
        try:
            ok, msg = check_fn()  # type: ignore[call-arg]
        except Exception as exc:  # pragma: no cover
            ok = False
            msg = f"Check raised an exception: {exc}"

        if ok is True:
            symbol = _CHECK
        elif ok is False:
            symbol = _FAIL
            any_failed = True
        else:
            symbol = _WARN  # None → warning, not a hard failure

        # Print first line with symbol, then indented continuation lines
        lines = msg.splitlines()
        print(f"  {symbol} {name}: {lines[0]}")
        for extra in lines[1:]:
            print(f"      {extra}")

    print()
    if any_failed:
        print("One or more checks failed — see fix suggestions above.")
        return 1

    print("All checks passed.")
    return 0
