"""Shared pytest fixtures for integration tests.

Provides HTTP clients (httpx.AsyncClient) for each service, base URL
fixtures driven by environment variables, and a seed_ids dict that
re-exports every deterministic UUID from seed_sandbox.py.

When the ``profiler`` fixture is active (provided by conftest_profiling.py),
each HTTP client is wrapped in :class:`ProfiledAsyncClient` so that every
request is automatically timed and recorded.
"""

from __future__ import annotations

import os
from typing import Any

import httpx
import pytest
import pytest_asyncio

from tests.integration.profiler import EndpointProfiler
from tests.integration.seed_sandbox import (
    SEED_AGENT_IDS,
    SEED_APPROVAL_IDS,
    SEED_BROKER_ACCOUNT_ID,
    SEED_COMPANY_IDS,
    SEED_DOCUMENT_IDS,
    SEED_GLOBAL_EVENT_IDS,
    SEED_INGESTION_RUN_IDS,
    SEED_LOCKOUT_IDS,
    SEED_NOTIFICATION_IDS,
    SEED_ORDER_IDS,
    SEED_PORTFOLIO_SNAPSHOT_ID,
    SEED_POSITION_IDS,
    SEED_RECOMMENDATION_IDS,
    SEED_RISK_CONFIG_ID,
    SEED_RISK_SNAPSHOT_IDS,
    SEED_SAVED_QUERY_IDS,
    SEED_TRADING_DECISION_ID,
    SEED_TREND_IDS,
    SEED_VARIANT_IDS,
    SEED_WATCHLIST_IDS,
)

# ---------------------------------------------------------------------------
# ProfiledAsyncClient — transparent timing wrapper
# ---------------------------------------------------------------------------


class ProfiledAsyncClient:
    """Wraps :class:`httpx.AsyncClient` to record per-request timing.

    Every HTTP method call (get, post, put, patch, delete, head, options)
    is automatically timed via :meth:`EndpointProfiler.track` using the
    pattern ``"METHOD /path"``.

    Attribute access for anything not explicitly wrapped is forwarded to
    the underlying client so tests can still use ``client.base_url``,
    ``client.headers``, etc.
    """

    def __init__(self, client: httpx.AsyncClient, profiler: EndpointProfiler) -> None:
        self._client = client
        self._profiler = profiler

    # -- Proxied HTTP methods ------------------------------------------------

    async def get(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"GET {url}"):
            return await self._client.get(url, **kwargs)

    async def post(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"POST {url}"):
            return await self._client.post(url, **kwargs)

    async def put(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"PUT {url}"):
            return await self._client.put(url, **kwargs)

    async def patch(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"PATCH {url}"):
            return await self._client.patch(url, **kwargs)

    async def delete(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"DELETE {url}"):
            return await self._client.delete(url, **kwargs)

    async def head(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"HEAD {url}"):
            return await self._client.head(url, **kwargs)

    async def options(self, url: str, **kwargs: Any) -> httpx.Response:
        async with self._profiler.track(f"OPTIONS {url}"):
            return await self._client.options(url, **kwargs)

    # -- Transparent attribute forwarding ------------------------------------

    def __getattr__(self, name: str) -> Any:
        return getattr(self._client, name)


# ---------------------------------------------------------------------------
# URL fixtures — read from env vars set by the runner Job (runner.yaml)
# ---------------------------------------------------------------------------


@pytest.fixture
def query_api_url() -> str:
    """Base URL for the Query API service."""
    return os.environ.get("QUERY_API_URL", "http://localhost:8000")


@pytest.fixture
def registry_api_url() -> str:
    """Base URL for the Symbol Registry service."""
    return os.environ.get("REGISTRY_API_URL", "http://localhost:8001")


@pytest.fixture
def risk_api_url() -> str:
    """Base URL for the Risk Engine service."""
    return os.environ.get("RISK_API_URL", "http://localhost:8002")


@pytest.fixture
def trading_api_url() -> str:
    """Base URL for the Trading Engine service."""
    return os.environ.get("TRADING_API_URL", "http://localhost:8003")


# ---------------------------------------------------------------------------
# Async HTTP client fixtures — one per service, 30 s timeout
# Wrapped with ProfiledAsyncClient for automatic timing collection.
# ---------------------------------------------------------------------------


@pytest_asyncio.fixture
async def query_client(
    query_api_url: str, profiler: EndpointProfiler,
) -> ProfiledAsyncClient:
    """Profiled async HTTP client pointed at the Query API."""
    async with httpx.AsyncClient(base_url=query_api_url, timeout=30.0) as client:
        yield ProfiledAsyncClient(client, profiler)


@pytest_asyncio.fixture
async def registry_client(
    registry_api_url: str, profiler: EndpointProfiler,
) -> ProfiledAsyncClient:
    """Profiled async HTTP client pointed at the Symbol Registry."""
    async with httpx.AsyncClient(base_url=registry_api_url, timeout=30.0) as client:
        yield ProfiledAsyncClient(client, profiler)


@pytest_asyncio.fixture
async def risk_client(
    risk_api_url: str, profiler: EndpointProfiler,
) -> ProfiledAsyncClient:
    """Profiled async HTTP client pointed at the Risk Engine."""
    async with httpx.AsyncClient(base_url=risk_api_url, timeout=30.0) as client:
        yield ProfiledAsyncClient(client, profiler)


@pytest_asyncio.fixture
async def trading_client(
    trading_api_url: str, profiler: EndpointProfiler,
) -> ProfiledAsyncClient:
    """Profiled async HTTP client pointed at the Trading Engine."""
    async with httpx.AsyncClient(base_url=trading_api_url, timeout=30.0) as client:
        yield ProfiledAsyncClient(client, profiler)


# ---------------------------------------------------------------------------
# Seed ID lookup — single dict with all deterministic IDs from seed_sandbox
# ---------------------------------------------------------------------------


@pytest.fixture
def seed_ids() -> dict:
    """All deterministic seed IDs for assertion in integration tests."""
    return {
        "companies": SEED_COMPANY_IDS,
        "documents": SEED_DOCUMENT_IDS,
        "trends": SEED_TREND_IDS,
        "recommendations": SEED_RECOMMENDATION_IDS,
        "orders": SEED_ORDER_IDS,
        "positions": SEED_POSITION_IDS,
        "global_events": SEED_GLOBAL_EVENT_IDS,
        "agents": SEED_AGENT_IDS,
        "variants": SEED_VARIANT_IDS,
        "broker_account_id": SEED_BROKER_ACCOUNT_ID,
        "trading_decision_id": SEED_TRADING_DECISION_ID,
        "portfolio_snapshot_id": SEED_PORTFOLIO_SNAPSHOT_ID,
        "risk_config_id": SEED_RISK_CONFIG_ID,
        "watchlists": SEED_WATCHLIST_IDS,
        "approvals": SEED_APPROVAL_IDS,
        "lockouts": SEED_LOCKOUT_IDS,
        "notifications": SEED_NOTIFICATION_IDS,
        "ingestion_runs": SEED_INGESTION_RUN_IDS,
        "saved_queries": SEED_SAVED_QUERY_IDS,
        "risk_snapshots": SEED_RISK_SNAPSHOT_IDS,
    }
