import logging
from typing import Awaitable, Callable

from fastapi import FastAPI, Request, Response
from fastapi.staticfiles import StaticFiles

from config.settings import get_settings
from middleware.auth_session import AuthSessionMiddleware
from middleware.metrics import MetricsMiddleware
from middleware.validation import validate_json
from routes.auth import router as auth_router
from routes.dashboard import router as dashboard_router
from routes.calculations import router as calculations_router
from routes.imports import router as imports_router
from routes.exports import router as exports_router
from routes.projects import router as projects_router
from routes.reports import router as reports_router
from routes.scenarios import router as scenarios_router
from routes.ui import router as ui_router
from monitoring import router as monitoring_router
from services.bootstrap import bootstrap_admin, bootstrap_pricing_settings
from scripts.init_db import init_db as init_db_script

app = FastAPI()

app.add_middleware(AuthSessionMiddleware)
app.add_middleware(MetricsMiddleware)

logger = logging.getLogger(__name__)


@app.middleware("http")
async def json_validation(
    request: Request, call_next: Callable[[Request], Awaitable[Response]]
) -> Response:
    return await validate_json(request, call_next)


@app.get("/health", summary="Container health probe")
async def health() -> dict[str, str]:
    return {"status": "ok"}


@app.get("/favicon.ico", include_in_schema=False)
async def favicon() -> Response:
    static_directory = "static"
    img_directory = f"{static_directory}/img"
    favicon_img = "logo_32x32.png"
    return StaticFiles(directory=img_directory).lookup_path(favicon_img)[0]


@app.on_event("startup")
# TODO: use lifespan events for startup/shutdown tasks
async def ensure_admin_bootstrap() -> None:
    settings = get_settings()
    admin_settings = settings.admin_bootstrap_settings()
    pricing_metadata = settings.pricing_metadata()
    try:
        # Ensure DB schema/types/seeds required for bootstrapping exist.
        # The initializer is idempotent and safe to run on every startup.
        try:
            init_db_script()
        except Exception:
            logger.exception(
                "DB initializer failed; continuing to bootstrap (non-fatal)")

        role_result, admin_result = bootstrap_admin(settings=admin_settings)
        pricing_result = bootstrap_pricing_settings(metadata=pricing_metadata)
        logger.info(
            "Admin bootstrap completed: roles=%s created=%s updated=%s rotated=%s assigned=%s",
            role_result.ensured,
            admin_result.created_user,
            admin_result.updated_user,
            admin_result.password_rotated,
            admin_result.roles_granted,
        )
        # Avoid accessing ORM-managed attributes that may be detached outside
        # of the UnitOfWork/session scope. Attempt a safe extraction and
        # fall back to minimal logging if attributes are unavailable.
        try:
            seed = pricing_result.seed
            slug = getattr(seed.settings, "slug", None) if seed and getattr(
                seed, "settings", None) else None
            created = getattr(seed, "created", None)
            updated_fields = getattr(seed, "updated_fields", None)
            impurity_upserts = getattr(seed, "impurity_upserts", None)
            logger.info(
                "Pricing settings bootstrap completed: slug=%s created=%s updated_fields=%s impurity_upserts=%s projects_assigned=%s",
                slug,
                created,
                updated_fields,
                impurity_upserts,
                pricing_result.projects_assigned,
            )
        except Exception:
            logger.info(
                "Pricing settings bootstrap completed (partial): projects_assigned=%s",
                pricing_result.projects_assigned,
            )
    except Exception:  # pragma: no cover - defensive logging
        logger.exception(
            "Failed to bootstrap administrator or pricing settings")


app.include_router(dashboard_router)
app.include_router(calculations_router)
app.include_router(auth_router)
app.include_router(imports_router)
app.include_router(exports_router)
app.include_router(projects_router)
app.include_router(scenarios_router)
app.include_router(reports_router)
app.include_router(ui_router)
app.include_router(monitoring_router)

app.mount("/static", StaticFiles(directory="static"), name="static")
