from contextlib import asynccontextmanager
from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html
from fastapi.staticfiles import StaticFiles
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
import os

from app.core.config import settings
from app.core.database import init_db, check_db_connection
from app.api.v1.router import api_router


limiter = Limiter(key_func=get_remote_address, default_limits=["60/minute"])


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan: startup and shutdown tasks."""
    # Startup
    print("[START] StemGenius API starting up...")
    await init_db()
    connected = await check_db_connection()
    if connected:
        print("[OK] Database connected successfully")
    else:
        print("[WARN] Database connection failed - check configuration")
    yield
    # Shutdown
    print("[STOP] StemGenius API shutting down...")


app = FastAPI(
    title="StemGenius API",
    description="""
## StemGenius Educational Gaming Platform API

A comprehensive multi-role educational platform with:

- 🎮 **Games** — 2D, 3D, VR educational games across all subjects
- 👤 **Multi-role System** — Students, Parents, Teachers, Schools, Organizations, Admins
- 🆔 **Portable STEM IDs** — Students keep their ID when changing schools
- 📱 **Offline Mode** — Download content for offline play (freemium topics free, premium requires active subscription)
- 🏆 **Progress Tracking** — XP, levels, stars, awards, streaks
- 💳 **Freemium/Premium** — Subscription-based premium content

### Authentication
Use the `/api/v1/auth/login` endpoint to get a JWT token, then include it as:
```
Authorization: Bearer <your_token>
```

### Roles
- `student` — Play games, track progress
- `parent` — Link children, view progress, make payments
- `teacher` — Submit questions, view student progress
- `school` — Manage enrollments and teachers
- `organization` — Affiliate with schools, view reports
- `admin` — Platform management
- `super_admin` — Full system access
    """,
    version="1.0.0",
    docs_url=None,
    redoc_url=None,
    openapi_url=None,
    lifespan=lifespan,
)

# Rate limiting
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.CORS_ORIGINS,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    allow_headers=["*"],
)


# ===================== GLOBAL EXCEPTION HANDLERS =====================

@app.exception_handler(404)
async def not_found_handler(request: Request, exc):
    return JSONResponse(
        status_code=404,
        content={"detail": "The requested resource was not found"},
    )


@app.exception_handler(500)
async def internal_error_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=500,
        content={"detail": "An internal server error occurred. Please try again later."},
    )


# ===================== LOCAL SWAGGER DOCS =====================

@app.get("/api/v1/openapi.json", include_in_schema=False)
async def get_openapi_json():
    """Serve OpenAPI schema."""
    from fastapi.openapi.utils import get_openapi
    schema = get_openapi(
        title=app.title,
        version=app.version,
        description=app.description,
        routes=app.routes,
    )
    return JSONResponse(schema)


@app.get("/api/v1/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url="/api/v1/openapi.json",
        title="StemGenius API - Docs",
        swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
        swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
        swagger_favicon_url="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🧠</text></svg>",
    )


@app.get("/api/v1/redoc", include_in_schema=False)
async def redoc_html():
    return get_redoc_html(
        openapi_url="/api/v1/openapi.json",
        title="StemGenius API - ReDoc",
        redoc_js_url="https://unpkg.com/redoc@latest/bundles/redoc.standalone.js",
    )


# ===================== HEALTH & INFO ENDPOINTS =====================

@app.get("/api/v1", tags=["Health"])
@app.get("/api/v1/", tags=["Health"])
@app.get("/", tags=["Health"])
async def root():
    return {
        "name": "StemGenius API",
        "version": "1.0.0",
        "status": "running",
        "docs": "/api/v1/docs",
    }


@app.get("/api/v1/health", tags=["Health"])
@app.get("/health", tags=["Health"])
async def health_check():
    """Check API and database health."""
    db_ok = await check_db_connection()
    return {
        "status": "healthy" if db_ok else "degraded",
        "api": "ok",
        "database": "ok" if db_ok else "error",
        "version": "1.0.0",
    }


# ===================== MOUNT API ROUTER =====================

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

# ===================== STATIC FILE SERVING =====================
# Serve uploaded assets at /uploads/<filename>
UPLOADS_DIR = os.path.join(os.path.dirname(__file__), "..", "uploads")
os.makedirs(UPLOADS_DIR, exist_ok=True)
app.mount("/uploads", StaticFiles(directory=UPLOADS_DIR), name="uploads")
