from __future__ import annotations

from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.middleware.cors import CORSMiddleware

from app.api.v1 import (
    academics, analytics, applications, auth, documents, finance, mentorship,
    partners, registrar, support, upload, verification, users, students, waitlist
)
from app.config import settings


def create_app() -> FastAPI:
    app = FastAPI(
        title=settings.app_name,
        description="Proconnect Open University Backend API",
        version="1.0.0",
    )

    # CORS middleware - handles OPTIONS automatically, but we add explicit handler as fallback
    app.add_middleware(
        CORSMiddleware,
        allow_origins=settings.allowed_origins_list,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
        expose_headers=["*"],
    )
    
    # Explicit OPTIONS handler for CORS preflight (catch-all, registered BEFORE other routes)
    # This ensures OPTIONS requests are handled even if CORS middleware fails
    @app.api_route("/{full_path:path}", methods=["OPTIONS"], include_in_schema=False)
    async def options_handler(full_path: str, request: Request):
        """Handle OPTIONS preflight requests for CORS."""
        origin = request.headers.get("origin")
        # Check if origin is in allowed list, otherwise use first allowed origin or wildcard
        allowed_origin = origin if origin and origin in settings.allowed_origins_list else (settings.allowed_origins_list[0] if settings.allowed_origins_list else "*")
        return Response(
            status_code=200,
            headers={
                "Access-Control-Allow-Origin": allowed_origin,
                "Access-Control-Allow-Credentials": "true",
                "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
                "Access-Control-Allow-Headers": "Authorization, Content-Type, Accept, Origin, X-Requested-With",
                "Access-Control-Max-Age": "3600",
            }
        )
    
    # Also handle root OPTIONS explicitly
    @app.options("/", include_in_schema=False)
    async def root_options(request: Request):
        """Handle OPTIONS preflight for root."""
        origin = request.headers.get("origin")
        # Check if origin is in allowed list, otherwise use first allowed origin or wildcard
        allowed_origin = origin if origin and origin in settings.allowed_origins_list else (settings.allowed_origins_list[0] if settings.allowed_origins_list else "*")
        return Response(
            status_code=200,
            headers={
                "Access-Control-Allow-Origin": allowed_origin,
                "Access-Control-Allow-Credentials": "true",
                "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
                "Access-Control-Allow-Headers": "Authorization, Content-Type, Accept, Origin, X-Requested-With",
                "Access-Control-Max-Age": "3600",
            }
        )

    # CORS headers for error responses
    def _cors_headers(origin: str | None) -> dict:
        allowed_origin = origin if origin and origin in settings.allowed_origins_list else (settings.allowed_origins_list[0] if settings.allowed_origins_list else "*")
        return {
            "Access-Control-Allow-Origin": allowed_origin,
            "Access-Control-Allow-Credentials": "true",
            "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
            "Access-Control-Allow-Headers": "Authorization, Content-Type, Accept, Origin, X-Requested-With",
        }

    @app.exception_handler(HTTPException)
    async def http_exception_handler(request: Request, exc: HTTPException):
        """Ensure CORS headers on HTTPException responses."""
        from fastapi.responses import JSONResponse
        origin = request.headers.get("origin")
        return JSONResponse(
            status_code=exc.status_code,
            content={"detail": exc.detail} if isinstance(exc.detail, str) else {"detail": str(exc.detail)},
            headers=_cors_headers(origin),
        )

    @app.exception_handler(Exception)
    async def global_exception_handler(request: Request, exc: Exception):
        """Handle all exceptions with user-friendly messages; log full error server-side only."""
        from fastapi import status
        from fastapi.responses import JSONResponse
        import logging
        import traceback

        origin = request.headers.get("origin")
        # Log full error for debugging (server-side only)
        logging.getLogger(__name__).exception("Unhandled exception: %s", exc)

        # User-friendly message: never expose DB/technical details to the client
        user_message = "We're temporarily unable to process your request. Please try again in a few minutes."

        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content={"detail": user_message},
            headers=_cors_headers(origin),
        )

    # Health check endpoint
    @app.get("/health")
    def health():
        return {"status": "ok", "service": settings.app_name}

    # API routes
    app.include_router(applications.router, prefix="/api/v1")
    app.include_router(auth.router, prefix="/api/v1")
    app.include_router(auth.unified_router, prefix="/api/v1")  # Unified auth for all user types
    app.include_router(verification.router, prefix="/api/v1")
    app.include_router(documents.router, prefix="/api/v1")
    app.include_router(users.router, prefix="/api/v1")
    app.include_router(students.router, prefix="/api/v1")
    app.include_router(waitlist.router, prefix="/api/v1")
    app.include_router(academics.router, prefix="/api/v1")
    app.include_router(finance.router, prefix="/api/v1")
    app.include_router(registrar.router, prefix="/api/v1")
    app.include_router(analytics.router, prefix="/api/v1")
    app.include_router(support.router, prefix="/api/v1")
    app.include_router(partners.router, prefix="/api/v1")
    app.include_router(mentorship.router, prefix="/api/v1")
    app.include_router(upload.router, prefix="/api/v1")

    return app


app = create_app()


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "app.main:app",
        host=settings.host,
        port=settings.port,
        reload=settings.environment == "development",
    )

