"""v0.4 Phase F pin tests.

:func:`bootstrap_for_test` is a thin opinionated wrapper over
:func:`bootstrap` with :meth:`MgfSettings.testing` defaults. The
test surface is small — three behaviours pinned:

  1. Default identity + settings shape.
  2. Override semantics (explicit args + custom settings).
  3. Returns the same :class:`AppContext` that ``current_context()``
     reports (Phase A invariant carried through).
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

import mgf.common
from mgf.common._lifecycle import AppContext
from mgf.common.settings import LoggingSettings, MgfSettings

if TYPE_CHECKING:
    from pathlib import Path


@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:
    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 TestBootstrapForTest:
    """Thin opinionated wrapper over ``bootstrap``."""

    def test_default_identity(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        ctx = mgf.common.bootstrap_for_test()
        try:
            assert ctx.app_name == "test-app"
            assert ctx.app_version == "0.0.1"
        finally:
            ctx.shutdown()

    def test_default_settings_match_testing_factory(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """Defaults: WARNING-level logging, OTel off, explicit preset."""
        ctx = mgf.common.bootstrap_for_test()
        try:
            assert ctx.settings.preset == "explicit"
            assert ctx.settings.logging.level == "WARNING"
            assert ctx.settings.otel.enabled is False
        finally:
            ctx.shutdown()

    def test_explicit_identity_override(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        ctx = mgf.common.bootstrap_for_test(
            app_name="my-test",
            app_version="9.9.9",
        )
        try:
            assert ctx.app_name == "my-test"
            assert ctx.app_version == "9.9.9"
        finally:
            ctx.shutdown()

    def test_explicit_settings_override(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """Pass a custom MgfSettings — the helper does NOT clobber it."""
        custom = MgfSettings.testing(logging=LoggingSettings(level="DEBUG"))
        ctx = mgf.common.bootstrap_for_test(settings=custom)
        try:
            assert ctx.settings.logging.level == "DEBUG"
        finally:
            ctx.shutdown()

    def test_returns_appcontext_directly(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """Phase A invariant: returns the live AppContext, not a wrapper."""
        ctx = mgf.common.bootstrap_for_test()
        try:
            assert type(ctx) is AppContext
            assert mgf.common.current_context() is ctx
        finally:
            ctx.shutdown()

    def test_works_as_context_manager(
        self,
        _isolated_state: Path,
        _isolated_logging: None,
        _isolated_excepthook: None,
    ) -> None:
        """``with bootstrap_for_test() as ctx:`` — same shape as
        ``with bootstrap() as ctx:``."""
        with mgf.common.bootstrap_for_test() as ctx:
            assert mgf.common.current_context() is ctx
        # After exit: shutdown was called.
        assert mgf.common.current_context() is None

    def test_in_all(self) -> None:
        """``bootstrap_for_test`` is exposed on the top-level package."""
        assert "bootstrap_for_test" in mgf.common.__all__
