"""v0.4 Phase A pin tests.

Two changes:

  1. ``bootstrap()`` returns an :class:`AppContext` directly — the
     v0.3 ``_BootstrapContext`` wrapper is gone. Both
     ``with bootstrap(...) as ctx:`` and ``ctx = bootstrap(...)``
     yield the same type, and that type is the public
     :class:`AppContext`.

  2. The diagnostic-CLI provenance helpers (``field_provenance``,
     ``env_vars_known_to_mgf``, ``FieldSource``, ``SourceKind``)
     are now public on ``mgf.common.cli`` so consumers can build
     their own settings-debug tooling without reaching past us.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

import mgf.common
import mgf.common.cli
from mgf.common._lifecycle import AppContext

if TYPE_CHECKING:
    from pathlib import Path


# ---------------------------------------------------------------------------
# A.1 — bootstrap() return type
# ---------------------------------------------------------------------------


@pytest.fixture
def _isolated_state(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> Path:
    monkeypatch.setenv("XDG_STATE_HOME", str(tmp_path / "state"))
    monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "config"))
    return tmp_path


@pytest.fixture
def _isolated_logging() -> None:
    """Reset root-logger handlers + identity around the test."""
    import logging as _logging

    from mgf.common import _identity

    prior_handlers = list(_logging.root.handlers)
    prior_level = _logging.root.level
    prior_app = _identity._APP_NAME
    prior_ver = _identity._APP_VERSION

    yield

    for h in list(_logging.root.handlers):
        _logging.root.removeHandler(h)
    for h in prior_handlers:
        _logging.root.addHandler(h)
    _logging.root.setLevel(prior_level)
    _identity._APP_NAME = prior_app
    _identity._APP_VERSION = prior_ver

    from mgf.common import _lifecycle

    _lifecycle._GLOBAL_CONTEXT = None


@pytest.fixture
def _isolated_excepthook() -> None:
    import sys
    import threading

    prior_sys = sys.excepthook
    prior_thread = threading.excepthook
    yield
    sys.excepthook = prior_sys
    threading.excepthook = prior_thread


class TestBootstrapReturnType:
    """A.1 — ``bootstrap()`` returns :class:`AppContext` directly."""

    def test_returns_appcontext_outside_with_block(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """``ctx = bootstrap(...)`` returns an AppContext, not a wrapper."""
        ctx = mgf.common.bootstrap(app_name="phase-a", app_version="0.4.0")
        try:
            assert type(ctx) is AppContext
            assert isinstance(ctx, AppContext)
        finally:
            ctx.shutdown()

    def test_with_block_yields_same_object(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """``with bootstrap(...) as ctx:`` yields the same AppContext
        that ``current_context()`` returns — no wrapper indirection."""
        with mgf.common.bootstrap(
            app_name="phase-a-with",
            app_version="0.4.0",
        ) as ctx:
            assert type(ctx) is AppContext
            # Strongest pin: identity check (was impossible while the
            # wrapper existed because current_context() returned the
            # inner AppContext but the with-clause yielded the wrapper).
            assert mgf.common.current_context() is ctx

    def test_oneshot_identity_matches_current_context(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """``ctx = bootstrap(...)`` is the same object as
        ``current_context()``. Was impossible while the wrapper existed."""
        ctx = mgf.common.bootstrap(app_name="oneshot", app_version="0.4.0")
        try:
            assert mgf.common.current_context() is ctx
        finally:
            ctx.shutdown()

    def test_no_private_wrapper_class_remains(self) -> None:
        """Pin: the v0.3 ``_BootstrapContext`` wrapper has been removed.

        If a future refactor reintroduces a wrapper, this test fails
        loudly — the goal is to keep the public type leak fixed.
        """
        from mgf.common import _lifecycle as _lc

        assert not hasattr(_lc, "_BootstrapContext"), (
            "v0.4 Phase A removed _BootstrapContext; do not re-add. "
            "If you need wrapping behaviour, extend AppContext directly."
        )


# ---------------------------------------------------------------------------
# A.3 — provenance helpers public on mgf.common.cli
# ---------------------------------------------------------------------------


class TestProvenancePublicSurface:
    """A.3 — the four provenance helpers are importable from the
    public path ``mgf.common.cli`` (formerly only available via
    the private ``mgf.common.cli._provenance``)."""

    def test_field_provenance_importable(self) -> None:
        from mgf.common.cli import field_provenance  # noqa: F401

    def test_env_vars_known_to_mgf_importable(self) -> None:
        from mgf.common.cli import env_vars_known_to_mgf  # noqa: F401

    def test_fieldsource_importable(self) -> None:
        from mgf.common.cli import FieldSource  # noqa: F401

    def test_sourcekind_importable(self) -> None:
        from mgf.common.cli import SourceKind  # noqa: F401

    def test_field_provenance_works_via_public_path(self) -> None:
        """End-to-end smoke: invoking via the public path produces
        the same shape as the private path (they ARE the same
        object — re-export, not duplicate)."""
        from mgf.common.cli import field_provenance as public_fn
        from mgf.common.cli._provenance import field_provenance as private_fn

        assert public_fn is private_fn

    def test_provenance_helpers_in_all(self) -> None:
        """Pin: AP-10 — the four new names appear in ``__all__``."""
        for name in (
            "field_provenance",
            "env_vars_known_to_mgf",
            "FieldSource",
            "SourceKind",
        ):
            assert name in mgf.common.cli.__all__, (
                f"v0.4 Phase A promoted {name!r} to public. It MUST "
                f"appear in mgf.common.cli.__all__."
            )
