import io
import shutil

import pytest
from rich.console import Console

from machine_backup import cli
from machine_backup.cli import cmd_doctor, run_doctor
from machine_backup.config import Config
from machine_backup.console import Reporter
from machine_backup.modules import postgres as pg_module


def _reporter():
    buf = io.StringIO()
    return Reporter(mode="linear", console=Console(file=buf, width=160)), buf


@pytest.fixture
def all_present(monkeypatch, tmp_path):
    monkeypatch.setattr(shutil, "which", lambda name: f"/usr/bin/{name}")
    monkeypatch.setattr(pg_module, "_find_pg_bin", lambda tool: f"/usr/bin/{tool}")
    monkeypatch.setattr(cli, "_probe_postgres", lambda: (True, "ok"))
    monkeypatch.setattr(cli, "_binary_version", lambda path: "v1.0")


def _cfg(tmp_path, identity=None):
    return Config(
        destination=tmp_path / "backups",
        age_recipient="age1abc",
        age_identity=identity,
    )


def test_doctor_all_good_exits_0(tmp_path, all_present):
    identity = tmp_path / "identity.txt"
    identity.write_text("AGE-SECRET-KEY-1FAKE")
    reporter, _ = _reporter()
    assert cmd_doctor(_cfg(tmp_path, identity), reporter) == 0


def test_doctor_missing_identity_is_critical(tmp_path, all_present):
    reporter, buf = _reporter()
    code = cmd_doctor(_cfg(tmp_path, tmp_path / "absente.txt"), reporter)
    assert code == 1
    assert "illisibles" in buf.getvalue()


def test_doctor_missing_recipient_is_critical(tmp_path, all_present):
    identity = tmp_path / "identity.txt"
    identity.write_text("x")
    cfg = Config(destination=tmp_path / "b", age_recipient=None, age_identity=identity)
    checks = run_doctor(cfg)
    recipient_check = next(c for c in checks if "publique" in c.name)
    assert recipient_check.critical and not recipient_check.ok


def test_doctor_missing_postgres_is_not_critical(tmp_path, monkeypatch):
    identity = tmp_path / "identity.txt"
    identity.write_text("x")
    monkeypatch.setattr(shutil, "which", lambda name: f"/usr/bin/{name}")
    monkeypatch.setattr(pg_module, "_find_pg_bin", lambda tool: None)
    monkeypatch.setattr(cli, "_probe_postgres", lambda: (False, "serveur eteint"))
    monkeypatch.setattr(cli, "_binary_version", lambda path: "v1.0")

    reporter, _ = _reporter()
    assert cmd_doctor(_cfg(tmp_path, identity), reporter) == 0

    checks = run_doctor(_cfg(tmp_path, identity))
    pg_checks = [c for c in checks if "PostgreSQL" in c.name]
    assert pg_checks and not any(c.critical for c in pg_checks)


def test_doctor_missing_core_binary_is_critical(tmp_path, monkeypatch):
    identity = tmp_path / "identity.txt"
    identity.write_text("x")
    monkeypatch.setattr(shutil, "which", lambda name: None)
    monkeypatch.setattr(pg_module, "_find_pg_bin", lambda tool: None)
    monkeypatch.setattr(cli, "_probe_postgres", lambda: (False, "absent"))

    reporter, _ = _reporter()
    assert cmd_doctor(_cfg(tmp_path, identity), reporter) == 1


def test_doctor_reports_log_directory(tmp_path, all_present):
    identity = tmp_path / "identity.txt"
    identity.write_text("x")
    checks = run_doctor(_cfg(tmp_path, identity))
    assert any("journaux" in c.name.lower() for c in checks)
