"""RA-03: concurrent bootstrap is single-shot per process.

`MgfCommonConfig.ready()` uses a module-level
`_BOOTSTRAP_LOCK` + `_BOOTSTRAP_STACK` guard to ensure the
`mgf.common.bootstrap` call fires exactly once even if Django's
app-registry build races (pytest-xdist + `--reuse-db`,
`override_settings(INSTALLED_APPS=...)` from a different thread,
future async-views re-entry).

This test fires N threads at `MgfCommonConfig().ready()` and
asserts the underlying `mgf.common.bootstrap` call counter
records exactly one invocation. A regression that drops the
lock — or that mistakenly re-bootstraps inside the same
process — fails the test.

(RA-03 in mgf-django's RELIABILITY_AND_ACCURACY tracker.)
"""

from __future__ import annotations

import contextlib
import threading
from contextlib import contextmanager
from typing import Any
from unittest.mock import patch


@contextmanager
def _bootstrap_call_counter():
    """Monkeypatch `mgf.common._lifecycle.bootstrap` with a counted
    no-op context manager; yield the counter object.

    Returning a context manager from the mock matches what
    `MgfCommonConfig.ready` actually does: `stack.enter_context(
    bootstrap(...))`.
    """
    counter = {"count": 0}

    @contextmanager
    def _fake_bootstrap(**kwargs: Any):
        counter["count"] += 1
        yield None

    with (
        patch(
            "mgf.common.bootstrap",
            side_effect=_fake_bootstrap,
        ) as mock_bootstrap,
        # Also patch the import inside _apps.py.
        patch(
            "mgf.common.bootstrap",
            side_effect=_fake_bootstrap,
            create=True,
        ),
    ):
        yield counter, mock_bootstrap


def _reset_bootstrap_guard() -> None:
    """Reset the module-level guard so the test starts clean."""
    from mgf.django import _apps

    with _apps._BOOTSTRAP_LOCK:
        if _apps._BOOTSTRAP_STACK is not None:
            with contextlib.suppress(Exception):
                _apps._BOOTSTRAP_STACK.close()
        _apps._BOOTSTRAP_STACK = None


class TestConcurrentBootstrap:
    """RA-03: N-thread race on MgfCommonConfig.ready() — bootstrap
    fires exactly once."""

    def test_n_threads_yield_single_bootstrap(self) -> None:
        """Fire 20 threads at ready(); assert bootstrap is called
        exactly once. A regression that drops `_BOOTSTRAP_LOCK` or
        re-enters `bootstrap` would record >1."""
        from django.apps import apps as django_apps

        _reset_bootstrap_guard()

        n_threads = 20
        barrier = threading.Barrier(n_threads)
        errors: list[BaseException] = []

        def _target() -> None:
            try:
                barrier.wait(timeout=5.0)
                # Re-fetch the app config every iteration so each
                # thread races on the same shared `ready()` path.
                django_apps.get_app_config("mgf_django").ready()
            except BaseException as exc:
                errors.append(exc)

        with _bootstrap_call_counter() as (counter, _mock_bootstrap):
            threads = [threading.Thread(target=_target) for _ in range(n_threads)]
            for t in threads:
                t.start()
            for t in threads:
                t.join(timeout=10.0)

        # No thread raised.
        assert not errors, (
            f"RA-03: {len(errors)} thread(s) raised: {[type(e).__name__ for e in errors]}"
        )

        # Bootstrap called EXACTLY once across N concurrent threads.
        assert counter["count"] == 1, (
            f"RA-03: expected exactly 1 bootstrap call across "
            f"{n_threads} threads, got {counter['count']}. The "
            f"`_BOOTSTRAP_LOCK` + `_BOOTSTRAP_STACK` guard is the "
            f"single-shot contract; a regression here breaks every "
            f"downstream Django consumer's startup."
        )

    def test_sequential_ready_calls_also_single_shot(self) -> None:
        """Sanity counter-test: the guard is single-shot regardless
        of threading. Two sequential ready() calls fire bootstrap once."""
        from django.apps import apps as django_apps

        _reset_bootstrap_guard()

        with _bootstrap_call_counter() as (counter, _):
            cfg = django_apps.get_app_config("mgf_django")
            cfg.ready()
            cfg.ready()  # second call → no-op per the guard

        assert counter["count"] == 1, (
            f"RA-03: sequential double-ready() should be single-shot; "
            f"got {counter['count']} bootstrap calls."
        )
