"""Shared fixtures for LLMHosts test suite."""

from __future__ import annotations

from datetime import datetime  # noqa: F401  -- needed for Pydantic model_rebuild
from typing import TYPE_CHECKING

import pytest
from httpx import ASGITransport, AsyncClient

from llmhosts.proxy.app import create_app
from llmhosts.proxy.dispatcher import BackendDispatcher

if TYPE_CHECKING:
    from pathlib import Path

# ---------------------------------------------------------------------------
# Fix Pydantic forward-reference resolution for models that use
# ``from __future__ import annotations`` with datetime in TYPE_CHECKING.
# ---------------------------------------------------------------------------
from llmhosts.cache.models import CacheEntry, CacheStats
from llmhosts.discovery.models import HardwareProfile, OllamaHealth
from llmhosts.proxy.dashboard_models import RequestDetailResponse, RequestLogItem
from llmhosts.router.models import BackendInfo
from llmhosts.topology.models import BackendNode, TopologySnapshot
from llmhosts.tunnel.models import TunnelStatus

CacheEntry.model_rebuild()
CacheStats.model_rebuild()
BackendInfo.model_rebuild()
RequestLogItem.model_rebuild()
RequestDetailResponse.model_rebuild()
HardwareProfile.model_rebuild()
OllamaHealth.model_rebuild()
BackendNode.model_rebuild()
TopologySnapshot.model_rebuild()
TunnelStatus.model_rebuild()


# ---------------------------------------------------------------------------
# App / client fixtures
# ---------------------------------------------------------------------------


@pytest.fixture()
def app():
    """Create a fresh FastAPI app for testing.

    Since httpx's ASGITransport does NOT trigger ASGI lifespan events,
    we manually create and attach a BackendDispatcher to app.state so
    that all routes that depend on ``request.app.state.dispatcher`` work.
    """
    application = create_app()
    return application


@pytest.fixture()
async def client(app):
    """Async HTTP client wired to the test app (no real server needed).

    Manually runs the lifespan (startup/shutdown) so that
    ``app.state.dispatcher`` is properly initialised.
    """
    # Manually create and initialise the dispatcher (no Ollama = 0 backends)
    dispatcher = BackendDispatcher()
    await dispatcher.startup()
    app.state.dispatcher = dispatcher

    transport = ASGITransport(app=app, raise_app_exceptions=False)
    async with AsyncClient(transport=transport, base_url="http://test") as ac:
        yield ac

    await dispatcher.shutdown()


# ---------------------------------------------------------------------------
# General-purpose fixtures
# ---------------------------------------------------------------------------


@pytest.fixture()
def tmp_llmhosts_dir(tmp_path: Path) -> Path:
    """Temporary .llmhosts directory for test isolation."""
    llmhosts_dir = tmp_path / ".llmhosts"
    llmhosts_dir.mkdir()
    return llmhosts_dir


@pytest.fixture()
def fresh_db(tmp_path: Path) -> Path:
    """Clean SQLite database path (doesn't exist yet -- callers create it)."""
    return tmp_path / "test.db"
