import logging
import re
import time
import uuid
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.responses import ORJSONResponse
from prometheus_client import make_asgi_app
from app.api.routes import router
from app.api.auth_routes import router as auth_router
from app.api.panel_routes import router as panel_router
from app.api.billing_routes import router as billing_router
from app.api.portal_routes import public_router as portal_router, admin_router as portal_admin_router
from app.api.finder_routes import public_router as finder_router, admin_router as finder_admin_router
from app.api.workspace_routes import router as workspace_router
from app.api.persona_routes import router as persona_router
from app.api.pro_routes import router as pro_router, integration_router as pro_integration_router
from app.api.editorial_routes import public_router as editorial_router, admin_router as editorial_admin_router
from app.api.verification_routes import public_router as verification_router, admin_router as verification_admin_router
from app.api.operations_routes import health_router as operations_health_router, admin_router as operations_admin_router
from app.api.contact_routes import router as contact_router
from app.api.reservation_routes import router as reservation_router
from app.core.config import get_settings
from app.services.mailer import notify_admin_error
from app.services.observability import observe_request


settings = get_settings()
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s")
app = FastAPI(title="Documenta API", version="1.24.3.4",
              docs_url="/docs" if settings.app_env != "production" else None,
              redoc_url=None, default_response_class=ORJSONResponse)
app.add_middleware(TrustedHostMiddleware, allowed_hosts=settings.hosts)
app.add_middleware(CORSMiddleware, allow_origins=settings.origins, allow_credentials=True,
                   allow_methods=["GET", "POST", "PUT", "DELETE"],
                   allow_headers=["Content-Type", "Authorization", "Idempotency-Key", "X-Access-Token", "X-CSRF-Token",
                                  "X-Documenta-Capability", "X-Documenta-Invitation"])


@app.middleware("http")
async def security_headers(request: Request, call_next):
    started = time.monotonic()
    requested_id = request.headers.get("X-Request-ID", "")[:64]
    correlation_id = requested_id if re.fullmatch(r"[A-Za-z0-9._-]{8,64}", requested_id) else str(uuid.uuid4())
    response = await call_next(request)
    response.headers["X-Request-ID"] = correlation_id
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
    response.headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()"
    response.headers["Content-Security-Policy"] = "default-src 'none'; frame-ancestors 'none'; base-uri 'none'"
    response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
    if request.url.path.startswith("/api/") and not request.url.path.startswith("/api/v1/portal/editorial/media/"):
        response.headers["Cache-Control"] = "no-store"
    observe_request(request, response.status_code, started)
    return response


app.include_router(router, prefix=settings.api_prefix)
app.include_router(auth_router, prefix=settings.api_prefix)
app.include_router(panel_router, prefix=settings.api_prefix)
app.include_router(billing_router, prefix=settings.api_prefix)
app.include_router(portal_router, prefix=settings.api_prefix)
app.include_router(portal_admin_router, prefix=settings.api_prefix)
app.include_router(finder_router, prefix=settings.api_prefix)
app.include_router(finder_admin_router, prefix=settings.api_prefix)
app.include_router(workspace_router, prefix=settings.api_prefix)
app.include_router(persona_router, prefix=settings.api_prefix)
app.include_router(pro_router, prefix=settings.api_prefix)
app.include_router(pro_integration_router, prefix=settings.api_prefix)
app.include_router(editorial_router, prefix=settings.api_prefix)
app.include_router(editorial_admin_router, prefix=settings.api_prefix)
app.include_router(verification_router, prefix=settings.api_prefix)
app.include_router(verification_admin_router, prefix=settings.api_prefix)
app.include_router(operations_health_router, prefix=settings.api_prefix)
app.include_router(operations_admin_router, prefix=settings.api_prefix)
app.include_router(contact_router, prefix=settings.api_prefix)
app.include_router(reservation_router, prefix=settings.api_prefix)
app.mount("/internal/metrics", make_asgi_app())


@app.exception_handler(Exception)
async def unhandled_error(request: Request, exc: Exception):
    requested_id = request.headers.get("X-Request-ID", "")[:64]
    correlation_id = requested_id if re.fullmatch(r"[A-Za-z0-9._-]{8,64}", requested_id) else str(uuid.uuid4())
    logging.exception("unhandled_error correlation_id=%s path=%s", correlation_id, request.url.path)
    try:
        notify_admin_error(correlation_id, "api", type(exc).__name__)
    except Exception:
        logging.exception("admin_error_notification_failed correlation_id=%s", correlation_id)
    return JSONResponse(status_code=500, content={"ok": False, "error": {
        "code": "INTERNAL_ERROR", "message": "No fue posible completar la solicitud."
    }, "request_id": correlation_id})
