"""MockFibinaci — captures spans in memory for test assertions."""
from __future__ import annotations

from typing import Any

from fibinaci._config import FibinaciConfig
from fibinaci._globals import _lock, shutdown
from fibinaci.buffer.memory_buffer import MemoryBuffer


class MockFibinaci:
    """Drop-in mock that captures all spans/outcomes in memory.

    Usage::

        mock = MockFibinaci()

        # Run your code that uses fibinaci.trace/span/instrument...

        spans = mock.get_spans()
        assert len(spans) == 3

        mock.teardown()
    """

    def __init__(self) -> None:
        self._buffer = MemoryBuffer(max_size=100_000)
        # Override globals to use our buffer with a no-op processor
        shutdown()

        from fibinaci import _globals

        with _lock:
            _globals._config = FibinaciConfig(api_key="mock_key", flush_interval=999)
            _globals._buffer = self._buffer
            _globals._processor = _NoOpProcessor()  # type: ignore[assignment]
            _globals._initialized = True

    def get_spans(self) -> list[dict[str, Any]]:
        """Return all captured span dicts."""
        return [s for s in self._buffer.peek() if s.get("_fibinaci_type") != "outcome"]

    def get_outcomes(self) -> list[dict[str, Any]]:
        """Return all captured outcome dicts."""
        return [s for s in self._buffer.peek() if s.get("_fibinaci_type") == "outcome"]

    def get_all(self) -> list[dict[str, Any]]:
        """Return all captured items (spans + outcomes)."""
        return self._buffer.peek()

    def clear(self) -> None:
        self._buffer.clear()

    def teardown(self) -> None:
        shutdown()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.teardown()


class _NoOpProcessor:
    """Processor that does nothing — spans stay in the buffer for assertions."""

    def start(self) -> None:
        pass

    def stop(self) -> None:
        pass
