"""Tests for `doctor --live` and `doctor --redaction` (the reader half)."""

from __future__ import annotations

import io
import json
from typing import TYPE_CHECKING

from mgf.common._doctor_snapshot import RUNTIME_SNAPSHOT_ENV_VAR
from mgf.common.cli._exit_codes import EXIT_OPERATION_ERROR, EXIT_SUCCESS

from mgf.fed.cli._doctor_live import doctor_live, doctor_redaction

if TYPE_CHECKING:
    from pathlib import Path

    import pytest


# ---------------------------------------------------------------------------
# doctor_live — read snapshot.
# ---------------------------------------------------------------------------


class TestDoctorLive:
    def test_returns_error_when_env_unset(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.delenv(RUNTIME_SNAPSHOT_ENV_VAR, raising=False)
        out = io.StringIO()
        rc = doctor_live(out=out)
        assert rc == EXIT_OPERATION_ERROR
        assert RUNTIME_SNAPSHOT_ENV_VAR in out.getvalue()

    def test_returns_error_when_file_missing(
        self,
        tmp_path: Path,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setenv(RUNTIME_SNAPSHOT_ENV_VAR, str(tmp_path / "nonexistent.json"))
        out = io.StringIO()
        rc = doctor_live(out=out)
        assert rc == EXIT_OPERATION_ERROR
        assert "does not exist" in out.getvalue()

    def test_returns_error_on_invalid_json(
        self,
        tmp_path: Path,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        path = tmp_path / "bad.json"
        path.write_text("not valid json {")
        monkeypatch.setenv(RUNTIME_SNAPSHOT_ENV_VAR, str(path))
        out = io.StringIO()
        rc = doctor_live(out=out)
        assert rc == EXIT_OPERATION_ERROR
        assert "Cannot read" in out.getvalue()

    def test_prints_snapshot_when_valid(
        self,
        tmp_path: Path,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        path = tmp_path / "runtime.json"
        snapshot = {
            "app_name": "myapp",
            "app_version": "1.0.0",
            "log_handler_count": 2,
            "otel_enabled": False,
        }
        path.write_text(json.dumps(snapshot))
        monkeypatch.setenv(RUNTIME_SNAPSHOT_ENV_VAR, str(path))
        out = io.StringIO()
        rc = doctor_live(out=out)
        assert rc == EXIT_SUCCESS
        printed = out.getvalue()
        assert "myapp" in printed
        assert "1.0.0" in printed
        assert "log_handler_count" in printed


# ---------------------------------------------------------------------------
# doctor_redaction — pipe payload through Redactor.
# ---------------------------------------------------------------------------


class TestDoctorRedaction:
    def test_redacts_authorization_header(self) -> None:
        out = io.StringIO()
        payload = json.dumps({"Authorization": "Bearer secret-xyz", "user": "alice"})
        rc = doctor_redaction(out=out, payload_text=payload)
        assert rc == EXIT_SUCCESS
        printed = out.getvalue()
        assert "Before redaction" in printed
        assert "After redaction" in printed
        # Either removed or masked — the standard Redactor handles
        # secret-shaped keys; we don't pin the exact mechanism.
        # Confirm the after-payload differs from the before-payload.
        before_idx = printed.find("Before")
        after_idx = printed.find("After")
        before_section = printed[before_idx:after_idx]
        after_section = printed[after_idx:]
        assert "Bearer secret-xyz" in before_section
        # Secret should NOT appear in the after section.
        assert "Bearer secret-xyz" not in after_section

    def test_no_redaction_warning(self) -> None:
        out = io.StringIO()
        payload = json.dumps({"user": "alice", "color": "blue"})
        rc = doctor_redaction(out=out, payload_text=payload)
        assert rc == EXIT_SUCCESS
        # Warns when nothing was redacted.
        assert "No fields were redacted" in out.getvalue()

    def test_returns_error_on_invalid_json(self) -> None:
        out = io.StringIO()
        rc = doctor_redaction(out=out, payload_text="not json")
        assert rc == EXIT_OPERATION_ERROR
        assert "JSON object" in out.getvalue() or "parse" in out.getvalue()

    def test_returns_error_on_non_object_json(self) -> None:
        out = io.StringIO()
        rc = doctor_redaction(out=out, payload_text="[1, 2, 3]")
        assert rc == EXIT_OPERATION_ERROR
        assert "OBJECT" in out.getvalue()
