from __future__ import annotations

from datetime import datetime, timezone

from fastapi import Depends, FastAPI, HTTPException, Query, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from uforia.api.models import ApiEnvelope, ApiMeta
from uforia.api.providers import ProviderRegistry
from uforia.api.providers.default import build_registry
from uforia.api.settings import ApiSettings, get_api_settings
from uforia.execution import (
    ExecutionCancelAllRequest,
    ExecutionCancelRequest,
    ExecutionIntent,
    ExecutionQuoteRequest,
)
from uforia.storage import DatasetStore


def create_app(
    settings: ApiSettings | None = None,
    store: DatasetStore | None = None,
    registry: ProviderRegistry | None = None,
) -> FastAPI:
    api_settings = settings or get_api_settings()
    api_store = store or DatasetStore(api_settings.data_root)
    provider_registry = registry or build_registry(api_store, api_settings)

    app = FastAPI(title="uforia API", version="0.1.0")
    app.state.settings = api_settings
    app.state.store = api_store
    app.state.registry = provider_registry
    app.add_middleware(
        CORSMiddleware,
        allow_origins=list(api_settings.cors_origins),
        allow_origin_regex=api_settings.cors_origin_regex,
        allow_credentials=False,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    def get_registry() -> ProviderRegistry:
        return app.state.registry

    @app.get("/api/v1/system/health")
    def system_health(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.run_provider.get_health(), query={})

    @app.get("/api/v1/signals")
    def list_signals(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.signal_provider.list_signals(), query={})

    @app.get("/api/v1/signals/{signal_id}/latest")
    def signal_latest(
        signal_id: str,
        source: str | None = None,
        symbol: str | None = None,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.signal_provider.get_latest(signal_id, source=source)
        except KeyError as exc:
            raise HTTPException(status_code=404, detail=f"Unknown signal: {signal_id}") from exc
        return _envelope(payload, query={"source": source, "symbol": symbol})

    @app.get("/api/v1/signals/{signal_id}/series")
    def signal_series(
        signal_id: str,
        source: str = "dvol",
        symbol: str | None = None,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.signal_provider.get_series(
                signal_id,
                source=source,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(status_code=404, detail=f"Unknown signal: {signal_id}") from exc
        return _envelope(
            payload,
            query={
                "source": source,
                "symbol": symbol,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/options/dashboards")
    def list_options_dashboards(
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.options_dashboard_provider.list_dashboards(), query={})

    @app.get("/api/v1/options/{dashboard_id}/latest")
    def options_dashboard_latest(
        dashboard_id: str,
        underlying: str | None = None,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.options_dashboard_provider.get_latest(
                dashboard_id,
                underlying=underlying,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown dashboard: {dashboard_id}",
            ) from exc
        return _envelope(payload, query={"underlying": underlying})

    @app.get("/api/v1/options/{dashboard_id}/series")
    def options_dashboard_series(
        dashboard_id: str,
        underlying: str | None = None,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.options_dashboard_provider.get_series(
                dashboard_id,
                underlying=underlying,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown dashboard: {dashboard_id}",
            ) from exc
        return _envelope(
            payload,
            query={
                "underlying": underlying,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/options/signals")
    def list_options_signals(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.options_signal_provider.list_signals(), query={})

    @app.get("/api/v1/options/signals/{signal_id}/latest")
    def options_signal_latest(
        signal_id: str,
        underlying: str = "BTC",
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.options_signal_provider.get_latest(signal_id, underlying=underlying)
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown options signal: {signal_id}",
            ) from exc
        return _envelope(payload, query={"underlying": underlying})

    @app.get("/api/v1/options/signals/{signal_id}/series")
    def options_signal_series(
        signal_id: str,
        underlying: str = "BTC",
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.options_signal_provider.get_series(
                signal_id,
                underlying=underlying,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown options signal: {signal_id}",
            ) from exc
        return _envelope(
            payload,
            query={
                "underlying": underlying,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/perps/dashboards")
    def list_perps_dashboards(
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.perps_dashboard_provider.list_dashboards(), query={})

    @app.get("/api/v1/perps/{dashboard_id}/latest")
    def perps_dashboard_latest(
        dashboard_id: str,
        asset: str = "BTC",
        venue_scope: str = "all",
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.perps_dashboard_provider.get_latest(
                dashboard_id,
                asset=asset.upper(),
                venue_scope=venue_scope,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404, detail=f"Unknown perps dashboard: {dashboard_id}"
            ) from exc
        return _envelope(payload, query={"asset": asset, "venue_scope": venue_scope})

    @app.get("/api/v1/perps/{dashboard_id}/series")
    def perps_dashboard_series(
        dashboard_id: str,
        asset: str = "BTC",
        venue_scope: str = "all",
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.perps_dashboard_provider.get_series(
                dashboard_id,
                asset=asset.upper(),
                venue_scope=venue_scope,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404, detail=f"Unknown perps dashboard: {dashboard_id}"
            ) from exc
        return _envelope(
            payload,
            query={
                "asset": asset,
                "venue_scope": venue_scope,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/perps/signals")
    def list_perps_signals(
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.perps_signal_provider.list_signals(), query={})

    @app.get("/api/v1/perps/signals/{signal_id}/latest")
    def perps_signal_latest(
        signal_id: str,
        asset: str = "BTC",
        venue_scope: str = "all",
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.perps_signal_provider.get_latest(
                signal_id,
                asset=asset.upper(),
                venue_scope=venue_scope,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404, detail=f"Unknown perps signal: {signal_id}"
            ) from exc
        return _envelope(payload, query={"asset": asset, "venue_scope": venue_scope})

    @app.get("/api/v1/perps/signals/{signal_id}/series")
    def perps_signal_series(
        signal_id: str,
        asset: str = "BTC",
        venue_scope: str = "all",
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.perps_signal_provider.get_series(
                signal_id,
                asset=asset.upper(),
                venue_scope=venue_scope,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404, detail=f"Unknown perps signal: {signal_id}"
            ) from exc
        return _envelope(
            payload,
            query={
                "asset": asset,
                "venue_scope": venue_scope,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/composite/signals")
    def list_composite_signals(
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.composite_provider.list_signals(), query={})

    @app.get("/api/v1/composite/signals/{signal_id}/latest")
    def composite_signal_latest(
        signal_id: str,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.composite_provider.get_latest(signal_id)
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown composite signal: {signal_id}",
            ) from exc
        return _envelope(payload, query={})

    @app.get("/api/v1/composite/signals/{signal_id}/series")
    def composite_signal_series(
        signal_id: str,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.composite_provider.get_series(
                signal_id,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown composite signal: {signal_id}",
            ) from exc
        return _envelope(
            payload,
            query={"start": start, "end": end, "quality": quality, "max_points": max_points},
        )

    @app.get("/api/v1/composite/decomposition/{signal_id}")
    def composite_decomposition(
        signal_id: str,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.composite_provider.get_decomposition(
                signal_id,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown composite signal: {signal_id}",
            ) from exc
        return _envelope(
            payload,
            query={"start": start, "end": end, "quality": quality, "max_points": max_points},
        )

    @app.get("/api/v1/composite/transitions/{signal_id}")
    def composite_transitions(
        signal_id: str,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.composite_provider.get_transitions(
                signal_id,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown composite signal: {signal_id}",
            ) from exc
        return _envelope(
            payload,
            query={"start": start, "end": end, "quality": quality, "max_points": max_points},
        )

    @app.get("/api/v1/execution/venues")
    def execution_venues(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.execution_provider.list_venues(), query={})

    @app.get("/api/v1/execution/markets")
    def execution_markets(
        venue: str | None = None,
        asset: str | None = None,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(
            providers.execution_provider.list_markets(venue=venue, asset=asset),
            query={"venue": venue, "asset": asset},
        )

    @app.get("/api/v1/execution/accounts")
    def execution_accounts(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.execution_provider.list_accounts(), query={})

    @app.get("/api/v1/execution/orders")
    def execution_orders(
        venue: str | None = None,
        account: str | None = None,
        asset: str | None = None,
        status: str | None = None,
        limit: int = Query(default=100, ge=1, le=1000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(
            providers.execution_provider.list_orders(
                venue=venue,
                account=account,
                asset=asset,
                status=status,
                limit=limit,
            ),
            query={
                "venue": venue,
                "account": account,
                "asset": asset,
                "status": status,
                "limit": limit,
            },
        )

    @app.get("/api/v1/execution/fills")
    def execution_fills(
        venue: str | None = None,
        account: str | None = None,
        asset: str | None = None,
        limit: int = Query(default=100, ge=1, le=1000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(
            providers.execution_provider.list_fills(
                venue=venue,
                account=account,
                asset=asset,
                limit=limit,
            ),
            query={"venue": venue, "account": account, "asset": asset, "limit": limit},
        )

    @app.get("/api/v1/execution/positions")
    def execution_positions(
        venue: str | None = None,
        account: str | None = None,
        asset: str | None = None,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(
            providers.execution_provider.list_positions(venue=venue, account=account, asset=asset),
            query={"venue": venue, "account": account, "asset": asset},
        )

    @app.get("/api/v1/execution/balances")
    def execution_balances(
        venue: str | None = None,
        account: str | None = None,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(
            providers.execution_provider.list_balances(venue=venue, account=account),
            query={"venue": venue, "account": account},
        )

    @app.get("/api/v1/execution/health")
    def execution_health(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.execution_provider.get_health(), query={})

    @app.post("/api/v1/execution/quote")
    def execution_quote(
        request: ExecutionQuoteRequest,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.execution_provider.request_quote(request), query={})

    @app.post("/api/v1/execution/order")
    def execution_order(
        request: ExecutionIntent,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.execution_provider.place_order(request), query={})

    @app.post("/api/v1/execution/cancel")
    def execution_cancel(
        request: ExecutionCancelRequest,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.execution_provider.cancel(request), query={})

    @app.post("/api/v1/execution/cancel-all")
    def execution_cancel_all(
        request: ExecutionCancelAllRequest,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.execution_provider.cancel_all(request), query={})

    @app.get("/api/v1/microstructure/signals")
    def list_microstructure_signals(
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.microstructure_provider.list_signals(), query={})

    @app.get("/api/v1/microstructure/signals/{signal_id}/latest")
    def microstructure_signal_latest(
        signal_id: str,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.microstructure_provider.get_latest(signal_id)
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown microstructure signal: {signal_id}",
            ) from exc
        return _envelope(payload, query={})

    @app.get("/api/v1/microstructure/signals/{signal_id}/series")
    def microstructure_signal_series(
        signal_id: str,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.microstructure_provider.get_series(
                signal_id,
                start=start,
                end=end,
                quality=quality,
                max_points=max_points,
            )
        except KeyError as exc:
            raise HTTPException(
                status_code=404,
                detail=f"Unknown microstructure signal: {signal_id}",
            ) from exc
        return _envelope(
            payload,
            query={
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/microstructure/features/{asset}")
    def microstructure_features(
        asset: str,
        horizon: str = "1m",
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        payload = providers.microstructure_provider.get_features(
            asset.upper(),
            horizon=horizon,
            start=start,
            end=end,
            quality=quality,
            max_points=max_points,
        )
        return _envelope(
            payload,
            query={
                "asset": asset,
                "horizon": horizon,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/microstructure/regime/{asset}")
    def microstructure_regime(
        asset: str,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        max_points: int | None = Query(default=None, ge=1, le=50000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        payload = providers.microstructure_provider.get_regime(
            asset.upper(),
            start=start,
            end=end,
            quality=quality,
            max_points=max_points,
        )
        return _envelope(
            payload,
            query={
                "asset": asset,
                "start": start,
                "end": end,
                "quality": quality,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/microstructure/health")
    def microstructure_health(
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        return _envelope(providers.microstructure_provider.get_health(), query={})

    @app.get("/api/v1/prices")
    def prices(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.price_provider.get_latest_prices(), query={})

    @app.get("/api/v1/prices/series")
    def price_series(
        asset: str = "BTC",
        venue_scope: str = "all",
        timeframe: str = "15m",
        start: datetime | None = None,
        end: datetime | None = None,
        max_points: int | None = Query(default=500, ge=1, le=5000),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        payload = providers.price_provider.get_price_series(
            asset.upper(),
            venue_scope=venue_scope,
            timeframe=timeframe,
            start=start,
            end=end,
            max_points=max_points,
        )
        return _envelope(
            payload,
            query={
                "asset": asset,
                "venue_scope": venue_scope,
                "timeframe": timeframe,
                "start": start,
                "end": end,
                "max_points": max_points,
            },
        )

    @app.get("/api/v1/microstructure/backtests")
    def microstructure_backtests(
        asset: str | None = None,
        horizon: str | None = None,
        limit: int = Query(default=50, ge=1, le=500),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        payload = providers.microstructure_provider.get_backtests(
            asset=asset.upper() if asset else None,
            horizon=horizon,
            limit=limit,
        )
        return _envelope(payload, query={"asset": asset, "horizon": horizon, "limit": limit})

    @app.get("/api/v1/microstructure/calibration/{asset}")
    def microstructure_calibration(
        asset: str,
        horizon: str | None = None,
        limit: int = Query(default=50, ge=1, le=500),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        payload = providers.microstructure_provider.get_calibration(
            asset.upper(),
            horizon=horizon,
            limit=limit,
        )
        return _envelope(payload, query={"asset": asset, "horizon": horizon, "limit": limit})

    @app.get("/api/v1/datasets")
    def list_datasets(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.dataset_provider.list_datasets(), query={})

    @app.get("/api/v1/datasets/{dataset_id}")
    def dataset_detail(
        dataset_id: str,
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.dataset_provider.get_dataset(dataset_id)
        except ValueError as exc:
            raise HTTPException(status_code=404, detail=f"Unknown dataset: {dataset_id}") from exc
        return _envelope(payload, query={})

    @app.get("/api/v1/datasets/{dataset_id}/rows")
    def dataset_rows(
        dataset_id: str,
        source: str | None = None,
        symbol: str | None = None,
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        limit: int = Query(50, ge=1, le=500),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        try:
            payload = providers.dataset_provider.get_rows(
                dataset_id,
                source=source,
                symbol=symbol,
                start=start,
                end=end,
                quality=quality,
                limit=limit,
            )
        except ValueError as exc:
            raise HTTPException(status_code=404, detail=f"Unknown dataset: {dataset_id}") from exc
        return _envelope(
            payload,
            query={
                "source": source,
                "symbol": symbol,
                "start": start,
                "end": end,
                "quality": quality,
                "limit": limit,
            },
        )

    @app.get("/api/v1/runs")
    def list_runs(
        start: datetime | None = None,
        end: datetime | None = None,
        quality: str | None = None,
        limit: int = Query(100, ge=1, le=500),
        providers: ProviderRegistry = Depends(get_registry),
    ) -> JSONResponse:
        payload = providers.run_provider.list_runs(
            start=start,
            end=end,
            quality=quality,
            limit=limit,
        )
        return _envelope(
            payload,
            query={"start": start, "end": end, "quality": quality, "limit": limit},
        )

    @app.get("/api/v1/runs/summary")
    def runs_summary(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.run_provider.get_summary(), query={})

    @app.get("/api/v1/engines")
    def engines(providers: ProviderRegistry = Depends(get_registry)) -> JSONResponse:
        return _envelope(providers.run_provider.list_engines(), query={})

    @app.websocket("/api/v1/stream")
    async def stream(websocket: WebSocket) -> None:
        await websocket.accept()
        try:
            async for event in app.state.registry.stream_provider.stream():
                await websocket.send_json(event.model_dump(mode="json"))
        except WebSocketDisconnect:
            return

    return app


def _envelope(data: object, *, query: dict[str, object]) -> JSONResponse:
    payload = ApiEnvelope(
        data=data,
        meta=ApiMeta(generated_at=datetime.now(tz=timezone.utc), query=query),
    )
    return JSONResponse(payload.model_dump(mode="json"))
