"""Tests for castor.doctor — health check system."""
from __future__ import annotations
from pathlib import Path
from unittest.mock import patch, MagicMock
import pytest

from castor.doctor import (
    CheckResult, DoctorReport,
    _check_python, _check_dep, _check_config,
    _check_opencastor_dir, _check_hardware_hailo,
    _check_hardware_oakd, _check_env_var,
    run_doctor, print_report,
)


# ── CheckResult / DoctorReport ───────────────────────────────────────────────

def test_check_result_fields():
    c = CheckResult("test", "ok", "all good", "no fix needed")
    assert c.name == "test"
    assert c.status == "ok"

def test_doctor_report_counts():
    r = DoctorReport(checks=[
        CheckResult("a", "ok"),
        CheckResult("b", "warn"),
        CheckResult("c", "fail"),
        CheckResult("d", "skip"),
    ])
    assert r.ok_count == 1
    assert r.warn_count == 1
    assert r.fail_count == 1
    assert not r.all_ok

def test_doctor_report_all_ok():
    r = DoctorReport(checks=[CheckResult("a", "ok"), CheckResult("b", "skip")])
    assert r.all_ok  # no failures

# ── _check_python ─────────────────────────────────────────────────────────────

def test_check_python_current():
    result = _check_python()
    assert result.status == "ok"  # we're running on 3.10+

# ── _check_dep ───────────────────────────────────────────────────────────────

def test_check_dep_present():
    result = _check_dep("json")  # stdlib, always present
    assert result.status == "ok"

def test_check_dep_absent():
    result = _check_dep("nonexistent_pkg_xyz_123")
    assert result.status == "warn"
    assert "pip install" in result.fix

# ── _check_config ─────────────────────────────────────────────────────────────

def test_check_config_found(tmp_path, monkeypatch):
    monkeypatch.chdir(tmp_path)
    (tmp_path / "bob.rcan.yaml").write_text("name: bob")
    result = _check_config()
    assert result.status == "ok"

def test_check_config_not_found(tmp_path, monkeypatch):
    monkeypatch.chdir(tmp_path)
    result = _check_config()
    assert result.status == "warn"
    assert "castor wizard" in result.fix

# ── _check_opencastor_dir ────────────────────────────────────────────────────

def test_check_opencastor_dir_present(tmp_path):
    d = tmp_path / ".opencastor"
    d.mkdir()
    (d / "config.yaml").write_text("")
    with patch("castor.doctor.Path.home", return_value=tmp_path):
        result = _check_opencastor_dir()
    assert result.status == "ok"

def test_check_opencastor_dir_missing(tmp_path):
    with patch("castor.doctor.Path.home", return_value=tmp_path):
        result = _check_opencastor_dir()
    assert result.status == "warn"

# ── _check_hardware_hailo ────────────────────────────────────────────────────

def test_check_hailo_present():
    with patch("castor.doctor.Path.exists", return_value=True):
        result = _check_hardware_hailo()
    assert result.status in ("ok", "skip")  # depends on actual hardware

def test_check_hailo_absent(tmp_path):
    fake_dev = tmp_path / "hailo0"
    # Don't create it — it shouldn't exist
    with patch("pathlib.Path.exists", lambda self: str(self) == str(tmp_path / "hailo0") and False):
        result = _check_hardware_hailo()
    # Skip or ok depending on actual /dev/hailo0
    assert result.status in ("ok", "skip")

# ── _check_env_var ────────────────────────────────────────────────────────────

def test_check_env_var_set(monkeypatch):
    monkeypatch.setenv("TEST_API_KEY_XYZ", "sk-test-12345")
    result = _check_env_var("TEST_API_KEY_XYZ")
    assert result.status == "ok"
    assert "sk-t" in result.detail  # truncated

def test_check_env_var_missing(monkeypatch, tmp_path):
    monkeypatch.delenv("MISSING_KEY_XYZ", raising=False)
    with patch("castor.doctor.Path.home", return_value=tmp_path):
        result = _check_env_var("MISSING_KEY_XYZ")
    assert result.status == "warn"

# ── run_doctor ────────────────────────────────────────────────────────────────

def test_run_doctor_returns_report():
    report = run_doctor()
    assert isinstance(report, DoctorReport)
    assert len(report.checks) >= 10

def test_run_doctor_full_returns_more_checks():
    r_basic = run_doctor(full=False)
    r_full = run_doctor(full=True)
    assert len(r_full.checks) >= len(r_basic.checks)

def test_print_report_no_crash():
    report = run_doctor()
    print_report(report)  # should not raise
