"""Shared fixtures for observability tests.

Two responsibilities:

1. **Configure identity per test.** Every observability module reads
   :func:`mgf.common.app_name` to derive log paths, env-var names,
   logger names, etc. Tests that don't configure identity would see
   the global default ("app") and produce paths the assertions don't
   expect. This conftest's autouse fixture sets a known test app name
   for every test under ``tests/unit/observability/`` and restores
   the prior value on teardown so the bare ``test_identity`` defaults
   tests stay clean.

2. **Single OTel TracerProvider for the session.** OpenTelemetry only
   allows ``set_tracer_provider`` to take effect ONCE per process.
   Two test modules each installing their own ``TracerProvider``
   would silently get the no-op proxy on the second install. This
   conftest installs the provider exactly once at session scope and
   exposes the in-memory exporter via the per-test ``in_memory_spans``
   fixture (which clears the buffer between tests).
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from mgf.common import _identity
from mgf.common.observability import otel_setup as otel_setup_mod

if TYPE_CHECKING:
    from collections.abc import Iterator
    from typing import Any

# Test app name — short, lowercase, no special chars so it works as a
# directory name AND as a logger-name prefix on every platform.
TEST_APP_NAME = "mgftest"


@pytest.fixture(autouse=True)
def _configure_test_identity() -> Iterator[None]:
    """Set a known app name for every observability test."""
    prior_name = _identity._APP_NAME
    prior_version = _identity._APP_VERSION
    _identity._set_identity(TEST_APP_NAME, "0.0.0")
    yield
    _identity._APP_NAME = prior_name
    _identity._APP_VERSION = prior_version


@pytest.fixture(scope="session")
def _session_tracer_provider() -> Iterator[Any]:
    """Install ONE TracerProvider for the whole pytest session.

    Yields the :class:`InMemorySpanExporter` so per-test fixtures
    can clear it between tests. ``otel_setup._INSTALLED`` is forced
    to ``True`` so :func:`mgf.common.observability.setup_otel` short-
    circuits and never tries to overwrite our test provider.
    """
    from opentelemetry import trace
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import SimpleSpanProcessor
    from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
        InMemorySpanExporter,
    )

    exporter = InMemorySpanExporter()
    provider = TracerProvider(resource=Resource.create({"service.name": "test"}))
    provider.add_span_processor(SimpleSpanProcessor(exporter))
    trace.set_tracer_provider(provider)
    prior_installed = otel_setup_mod._INSTALLED
    otel_setup_mod._INSTALLED = True
    try:
        yield exporter
    finally:
        otel_setup_mod._INSTALLED = prior_installed


@pytest.fixture
def in_memory_spans(_session_tracer_provider: Any) -> Iterator[Any]:
    """Per-test view of the session exporter — cleared between tests."""
    _session_tracer_provider.clear()
    yield _session_tracer_provider
