"""Additional tests for llmdebug public API helpers in __init__.py."""

from __future__ import annotations

import builtins
import importlib
import warnings
from typing import Any

import pytest

import llmdebug
from llmdebug.config import SnapshotConfig


def test_init_module_reload_executes_top_level_exports() -> None:
    reloaded = importlib.reload(llmdebug)
    assert reloaded.__version__
    assert "debug_snapshot" in reloaded.__all__
    assert "load_jupyter" in reloaded.__all__


def test_maybe_warn_about_unredacted_defaults_emits_once(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(llmdebug, "_unredacted_default_warning_emitted", False)

    with pytest.warns(UserWarning, match="no redaction settings were provided"):
        llmdebug._maybe_warn_about_unredacted_defaults(
            redaction_profile=None,
            redact=None,
            redact_keys=None,
            redact_traceback=None,
            redact_exception_strings=None,
        )

    with warnings.catch_warnings(record=True) as captured:
        warnings.simplefilter("always")
        llmdebug._maybe_warn_about_unredacted_defaults(
            redaction_profile=None,
            redact=None,
            redact_keys=None,
            redact_traceback=None,
            redact_exception_strings=None,
        )
    assert captured == []


def test_maybe_warn_about_unredacted_defaults_no_warning_when_inputs_present(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(llmdebug, "_unredacted_default_warning_emitted", False)
    with warnings.catch_warnings(record=True) as captured:
        warnings.simplefilter("always")
        llmdebug._maybe_warn_about_unredacted_defaults(
            redaction_profile="ci",
            redact=None,
            redact_keys=None,
            redact_traceback=None,
            redact_exception_strings=None,
        )
    assert captured == []


def test_try_capture_logs_when_capture_exception_fails(
    monkeypatch: pytest.MonkeyPatch,
    capsys: pytest.CaptureFixture[str],
) -> None:
    def _boom(*_args: Any, **_kwargs: Any) -> None:
        raise RuntimeError("capture exploded")

    monkeypatch.setattr(llmdebug, "capture_exception", _boom)
    cfg = SnapshotConfig()

    try:
        raise ValueError("trigger")
    except ValueError as exc:
        llmdebug._try_capture("api-test", exc, cfg)

    assert "capture failed for api-test: RuntimeError: capture exploded" in capsys.readouterr().err


def test_load_jupyter_forwards_kwargs(monkeypatch: pytest.MonkeyPatch) -> None:
    import llmdebug.jupyter_plugin as jp

    captured: list[dict[str, Any]] = []

    def _fake_install(**kwargs: Any) -> None:
        captured.append(kwargs)

    monkeypatch.setattr(jp, "install", _fake_install)
    llmdebug.load_jupyter(enable_auto_capture=False, detail="full")

    assert captured == [{"enable_auto_capture": False, "detail": "full"}]


def test_load_jupyter_raises_runtime_error_when_import_fails(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    real_import = builtins.__import__

    def _fake_import(
        name: str,
        globals: dict[str, Any] | None = None,
        locals: dict[str, Any] | None = None,
        fromlist: tuple[str, ...] = (),
        level: int = 0,
    ) -> Any:
        if name.endswith("jupyter_plugin"):
            raise ImportError("missing IPython")
        return real_import(name, globals, locals, fromlist, level)

    monkeypatch.setattr(builtins, "__import__", _fake_import)
    with pytest.raises(RuntimeError, match="IPython is not installed"):
        llmdebug.load_jupyter()


def test_ipython_extension_functions_forward(monkeypatch: pytest.MonkeyPatch) -> None:
    import llmdebug.jupyter_plugin as jp

    calls: list[tuple[str, object]] = []
    monkeypatch.setattr(jp, "load_ipython_extension", lambda ip: calls.append(("load", ip)))
    monkeypatch.setattr(jp, "unload_ipython_extension", lambda ip: calls.append(("unload", ip)))

    ip = object()
    llmdebug.load_ipython_extension(ip)
    llmdebug.unload_ipython_extension(ip)

    assert calls == [("load", ip), ("unload", ip)]
