"""Shared fixtures for unit tests."""

import platform
import sys
import time
from unittest.mock import MagicMock

import pytest

from tests.testkit.fixtures import record_store as record_store

# ---------------------------------------------------------------------------
# Unit-test suite target: ~3 minutes (180s). We warn if over, but do not
# fail (hard limits cause flaky CI on busy runners). See tests/unit/README.md.
# ---------------------------------------------------------------------------
UNIT_TEST_TARGET_SECONDS = 180
_suite_start: float | None = None


def pytest_sessionstart(session: pytest.Session) -> None:
    global _suite_start
    _suite_start = time.monotonic()


def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:
    global _suite_start
    if _suite_start is None:
        return
    elapsed = time.monotonic() - _suite_start
    if elapsed > UNIT_TEST_TARGET_SECONDS:
        msg = (
            f"\n*** WARNING: Unit suite took {elapsed:.1f}s (target <{UNIT_TEST_TARGET_SECONDS}s). "
            "See tests/unit/README.md and run 'pytest tests/unit -v --durations=20' to find slow tests.\n"
        )
        print(msg, file=sys.stderr, flush=True)


# Conditionally ignore MCP tests if fastmcp is not installed
# This must be done at collection time, before any imports from test files
try:
    import fastmcp  # noqa: F401
except ImportError:
    collect_ignore_glob = ["mcp/*"]


# Mock FuseOSError class
class FuseOSError(OSError):
    """Mock FuseOSError for testing."""

    def __init__(self, errno: int):
        """Initialize with errno."""
        self.errno = errno
        super().__init__(errno, f"FUSE error: {errno}")


# Mock the fuse module at import time (before any test imports happen)
# This ensures the fuse module is available when nexus.fuse modules are imported
_fuse_mock = MagicMock()
_fuse_mock.FUSE = MagicMock
_fuse_mock.Operations = object
_fuse_mock.FuseOSError = FuseOSError
sys.modules["fuse"] = _fuse_mock


def pytest_collection_modifyitems(items: list[pytest.Item]) -> None:
    """Apply collection-time suite adjustments."""


@pytest.fixture(autouse=True)
def mock_fuse_module():
    """Reset the fuse module mock before each test.

    This fixture automatically runs before each test to ensure
    a fresh fuse module mock, preventing test pollution.
    """
    # Reset the existing mock to clear any side_effects
    _fuse_mock.reset_mock()
    _fuse_mock.FUSE = MagicMock
    _fuse_mock.Operations = object
    _fuse_mock.FuseOSError = FuseOSError

    yield _fuse_mock

    # Cleanup happens automatically before next test


@pytest.fixture(autouse=True)
def isolate_test_database(monkeypatch):
    """Automatically isolate test databases from production environment.

    This fixture runs before every test to clear environment variables that
    would cause tests to connect to production databases instead of using
    the test-specific db_path parameters.

    This prevents test pollution where version numbers, file counts, etc.
    accumulate across test runs.
    """
    monkeypatch.delenv("NEXUS_DATABASE_URL", raising=False)
    monkeypatch.delenv("POSTGRES_URL", raising=False)
    monkeypatch.delenv("DATABASE_URL", raising=False)
    yield


@pytest.fixture(autouse=True)
def windows_db_cleanup():
    """Cleanup fixture for Windows database tests.

    Automatically runs after each test on Windows to release database connections.
    Minimal overhead approach - just GC, no delay since close() should handle everything.
    """
    import gc

    yield

    # Only do GC on Windows to ensure connections are released
    if platform.system() == "Windows":
        # Force garbage collection to release any lingering database connections
        # With proper close() calls in NexusFS, this should be enough
        gc.collect()


@pytest.fixture
def isolated_db(tmp_path, monkeypatch):
    """Create an isolated database path for tests that need guaranteed fresh state.

    This fixture ensures each test gets a completely unique database path
    to prevent any cross-test pollution. It also clears environment variables
    that could override the database path (NEXUS_DATABASE_URL, POSTGRES_URL).
    The database is automatically cleaned up after the test completes.

    Usage:
        async def test_something(isolated_db, tmp_path):
            nx = make_test_nexus(tmp_path, use_raft=True)
            # Test code here
            nx.close()

    Returns:
        Path: Unique database file path in temporary directory
    """
    import uuid

    # Clear environment variables that would override db_path
    monkeypatch.delenv("NEXUS_DATABASE_URL", raising=False)
    monkeypatch.delenv("POSTGRES_URL", raising=False)
    monkeypatch.delenv("DATABASE_URL", raising=False)

    unique_id = str(uuid.uuid4())[:8]
    db_path = tmp_path / f"test_db_{unique_id}.db"

    yield db_path

    # Clean up database file after test
    if db_path.exists():
        from contextlib import suppress

        with suppress(Exception):  # Best effort cleanup
            db_path.unlink()
