"""FastAPI application for the Fluxibly Monitoring Dashboard."""

from __future__ import annotations

import json
from contextlib import asynccontextmanager
from decimal import Decimal
from pathlib import Path
from typing import Any

try:
    from fastapi import FastAPI
    from fastapi.staticfiles import StaticFiles
    from fastapi.templating import Jinja2Templates
except ImportError as e:
    raise ImportError(
        "FastAPI is required for the monitoring dashboard. "
        "Install it with: pip install fluxibly[monitoring]"
    ) from e

from markupsafe import Markup, escape

from fluxibly.monitoring.config import MonitoringConfig


def _json_default(obj: Any) -> Any:
    """JSON serializer for types not handled by default."""
    if isinstance(obj, Decimal):
        return float(obj)
    return str(obj)


def pretty_json(value: Any) -> Markup:
    """Jinja2 filter: render any value as pretty-printed JSON.

    Handles dicts, lists, and JSON-encoded strings from the DB.
    """
    if value is None:
        return Markup("")
    # If it's a string, try to parse it as JSON first
    if isinstance(value, str):
        try:
            value = json.loads(value)
        except (json.JSONDecodeError, TypeError):
            return Markup(escape(value))
    formatted = json.dumps(
        value, indent=2, default=_json_default, ensure_ascii=False
    )
    return Markup(escape(formatted))


_DASHBOARD_DIR = Path(__file__).parent
_TEMPLATES_DIR = _DASHBOARD_DIR / "templates"
_STATIC_DIR = _DASHBOARD_DIR / "static"


def create_app(config: MonitoringConfig | None = None) -> FastAPI:
    """Create the FastAPI dashboard application.

    Args:
        config: MonitoringConfig. If None, loads from environment.

    Returns:
        Configured FastAPI app.
    """
    if config is None:
        config = MonitoringConfig.from_env()

    @asynccontextmanager
    async def lifespan(app: FastAPI):  # type: ignore[no-untyped-def]
        # Startup: create DB pool
        from fluxibly.monitoring.db.connection import get_pool
        from fluxibly.monitoring.db.repository import MonitoringRepository

        pool = await get_pool(config.to_connect_kwargs())
        app.state.repo = MonitoringRepository(pool)
        app.state.config = config
        yield
        # Shutdown
        from fluxibly.monitoring.db.connection import close_all_pools

        await close_all_pools()

    app = FastAPI(
        title="Fluxibly Monitoring Dashboard",
        version="1.0.0",
        lifespan=lifespan,
    )

    # Static files
    if _STATIC_DIR.exists():
        app.mount(
            "/static", StaticFiles(directory=str(_STATIC_DIR)), name="static"
        )

    # Templates
    templates = Jinja2Templates(directory=str(_TEMPLATES_DIR))
    templates.env.filters["pretty_json"] = pretty_json
    app.state.templates = templates

    # Register routes
    from fluxibly.monitoring.dashboard.routes.analytics import (
        router as analytics_router,
    )
    from fluxibly.monitoring.dashboard.routes.api import router as api_router
    from fluxibly.monitoring.dashboard.routes.traces import (
        router as traces_router,
    )

    app.include_router(api_router, prefix="/api")
    app.include_router(traces_router)
    app.include_router(analytics_router)

    return app
