"""``mgf-fed app-doctor --live`` and ``--redaction`` implementations.

See: ``docs/reference/cli.md`` (recipe forthcoming in v0.5 Phase F).

These two diagnostic flags close the v0.5 strategic-review §3.5
(superior self-awareness) findings: consumers can't introspect a
running process's wiring, and there's no way to verify redaction
coverage short of reading source.

``--live``
    Reads the runtime snapshot from the path stored in
    ``MGF_DOCTOR_RUNTIME_PATH`` (off by default — opt-in via env
    var at bootstrap time). The snapshot is written by
    :func:`mgf.common._doctor_snapshot.emit_runtime_snapshot` after
    successful wiring and refreshed on ``AppContext.reload()``. Prints
    what was wired: app identity, log handlers, OTel endpoint,
    redaction patterns, registered subcommands.

``--redaction``
    Reads a JSON payload from stdin, runs it through the standard
    :class:`Redactor`, prints before + after side-by-side. Useful
    for "is my Authorization header being redacted?" in 30 seconds.

NOTE: this is the *reader* half — the bootstrap-side *writer*
(:func:`emit_runtime_snapshot`) lives at the library root in
``mgf.common._doctor_snapshot`` so the runtime library never imports
the CLI command surface.
"""

from __future__ import annotations

import json
import os
import sys
from pathlib import Path
from typing import TYPE_CHECKING, Any

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

if TYPE_CHECKING:
    import io


def doctor_live(*, out: io.TextIOBase | None = None) -> int:
    """Print the runtime snapshot referenced by ``MGF_DOCTOR_RUNTIME_PATH``.

    Returns :data:`EXIT_SUCCESS` if the snapshot is read + printed.
    Returns :data:`EXIT_OPERATION_ERROR` if the env var is unset, the
    file is missing, or the contents aren't valid JSON.
    """
    if out is None:
        out = sys.stdout  # type: ignore[assignment]
    assert out is not None

    path_str = os.environ.get(RUNTIME_SNAPSHOT_ENV_VAR)
    if not path_str:
        print(
            f"✗ {RUNTIME_SNAPSHOT_ENV_VAR} not set. To enable runtime "
            "snapshots, set the env var to a writable path BEFORE "
            "calling bootstrap() in the target process. Example:\n"
            f"   export {RUNTIME_SNAPSHOT_ENV_VAR}=/tmp/mgf-runtime.json",
            file=out,
        )
        return EXIT_OPERATION_ERROR

    path = Path(path_str)
    if not path.exists():
        print(
            f"✗ Runtime snapshot file does not exist: {path}\n"
            f"   Has the target process called bootstrap() yet? "
            f"({RUNTIME_SNAPSHOT_ENV_VAR}={path_str})",
            file=out,
        )
        return EXIT_OPERATION_ERROR

    try:
        snapshot = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, ValueError) as exc:
        print(f"✗ Cannot read snapshot at {path}: {exc}", file=out)
        return EXIT_OPERATION_ERROR

    print(f"Live snapshot from {path}:", file=out)
    print(file=out)
    print(json.dumps(snapshot, indent=2, sort_keys=True), file=out)
    return EXIT_SUCCESS


def doctor_redaction(
    *,
    out: io.TextIOBase | None = None,
    payload_text: str | None = None,
) -> int:
    """Read a JSON payload, run it through the default Redactor, print before/after.

    ``payload_text`` is for testing — when None, reads from stdin.

    Returns :data:`EXIT_SUCCESS` even if the payload was not redacted
    (the consumer's expectation is "show me what gets redacted"; an
    empty redaction is information, not an error). Returns
    :data:`EXIT_OPERATION_ERROR` if stdin doesn't parse as JSON.
    """
    if out is None:
        out = sys.stdout  # type: ignore[assignment]
    assert out is not None

    if payload_text is None:
        payload_text = sys.stdin.read()

    try:
        payload: dict[str, Any] = json.loads(payload_text)
    except ValueError as exc:
        print(
            f"✗ stdin must be a JSON object; failed to parse: {exc}\n"
            f"   Example:\n"
            f'   echo \'{{"Authorization": "Bearer secret", "user": "alice"}}\' | '
            "mgf-fed app-doctor --redaction",
            file=out,
        )
        return EXIT_OPERATION_ERROR

    if not isinstance(payload, dict):
        print(
            f"✗ stdin must be a JSON OBJECT; got {type(payload).__name__}.",
            file=out,
        )
        return EXIT_OPERATION_ERROR

    from mgf.common.observability.redaction import Redactor

    before = json.dumps(payload, indent=2, sort_keys=True)
    redactor = Redactor()
    redacted = dict(payload)  # Redactor.redact mutates in-place.
    redactor.redact(redacted)
    after = json.dumps(redacted, indent=2, sort_keys=True)

    print("Before redaction:", file=out)
    print(before, file=out)
    print(file=out)
    print("After redaction:", file=out)
    print(after, file=out)
    print(file=out)

    redacted_keys = sorted(set(payload.keys()) - set(redacted.keys()))
    masked_keys = sorted(k for k in payload if k in redacted and payload[k] != redacted[k])
    if redacted_keys or masked_keys:
        print("Effect:", file=out)
        for k in redacted_keys:
            print(f"  - removed: {k}", file=out)
        for k in masked_keys:
            print(f"  - masked:  {k}", file=out)
    else:
        print(
            "⚠ No fields were redacted. Either the payload contains no "
            "secret-shaped keys, or the configured redaction patterns "
            "don't cover this shape. Inspect "
            "DEFAULT_REDACTION_KEYS or extend via "
            "register_redaction_pattern_group().",
            file=out,
        )

    return EXIT_SUCCESS


__all__ = [
    "RUNTIME_SNAPSHOT_ENV_VAR",
    "doctor_live",
    "doctor_redaction",
]
