from contextlib import asynccontextmanager
from urllib.parse import urlparse, parse_qs

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.core.install_secrets import ensure_install_secrets
from app.core.config import settings
from app.core.jwt_denylist import ensure_jwt_revocation_backend
from app.core.app_settings import bootstrap_settings
from app.core.storage import ensure_bucket
from app.core import database as db_module
from app.db.token_cleanup import cleanup_expired_tokens
from app.db.base import Base
from app.db import models as _models  # noqa: F401
from app.db.seed import run_seed
from app.modules.auth.router import router as auth_router
from app.modules.users.router import router as users_router
from app.modules.content.router import router as content_router
from app.modules.admin.router import router as admin_router
from app.modules.media.router import router as media_router
from app.modules.test.router import router as test_router


def _assert_production_guards() -> None:
    if settings.app_env.lower() != "production":
        return
    if settings.enable_test_routes:
        raise RuntimeError("ENABLE_TEST_ROUTES must be false in production")
    if settings.enable_docs:
        raise RuntimeError("ENABLE_DOCS must be false in production")
    if not settings.enable_rate_limit:
        raise RuntimeError("ENABLE_RATE_LIMIT must be true in production")
    if not settings.cookie_secure:
        raise RuntimeError("COOKIE_SECURE must be true in production")
    if settings.jwt_access_secret.startswith("change-me-"):
        raise RuntimeError("JWT_ACCESS_SECRET placeholder is not allowed in production")
    if settings.jwt_refresh_pepper.startswith("change-me-"):
        raise RuntimeError("JWT_REFRESH_PEPPER placeholder is not allowed in production")
    parsed = urlparse(settings.database_url)
    if parsed.username == "user" and parsed.password == "pass":
        raise RuntimeError("Default database credentials are not allowed in production")
    if parsed.scheme.startswith("postgresql"):
        sslmode = parse_qs(parsed.query).get("sslmode", [""])[0]
        if sslmode != "require":
            raise RuntimeError("DATABASE_URL must contain sslmode=require in production")


def create_app() -> FastAPI:
    @asynccontextmanager
    async def lifespan(_: FastAPI):
        ensure_install_secrets()
        bootstrap_settings()
        ensure_jwt_revocation_backend()
        _assert_production_guards()
        if settings.enable_test_routes:
            Base.metadata.create_all(db_module.engine)
        run_seed()
        cleanup_expired_tokens()
        ensure_bucket()
        yield

    app = FastAPI(
        title="Compton API",
        version="1.0.0",
        docs_url="/api/v1/docs" if settings.enable_docs else None,
        openapi_url="/api/v1/openapi.json" if settings.enable_docs else None,
        lifespan=lifespan,
    )
    app.add_middleware(
        CORSMiddleware,
        allow_origins=settings.cors_origins,
        allow_credentials=True,
        allow_methods=["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
        allow_headers=["Authorization", "Content-Type", "X-Request-ID"],
    )

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

    app.include_router(auth_router, prefix="/api/v1/auth", tags=["auth"])
    app.include_router(users_router, prefix="/api/v1/users", tags=["users"])
    app.include_router(content_router, prefix="/api/v1/content", tags=["content"])
    app.include_router(admin_router, prefix="/api/v1/admin", tags=["admin"])
    app.include_router(media_router, prefix="/api/v1/media", tags=["media"])
    if settings.enable_test_routes:
        app.include_router(test_router, prefix="/api/v1/test", tags=["test"])
    return app


app = create_app()
