# Educational snapshot of the lesson-reading API.
# Configure AUTH0_DOMAIN, AUTH0_AUDIENCE, AUTH0_CLIENT_ID and FRONTEND_ORIGIN.
# Dependencies used: fastapi>=0.115.11,<1; uvicorn>=0.30,<1;
# auth0-fastapi-api==1.0.0b9. The lesson documents the tested session version.
# No Firestore or progress endpoints are included in this milestone.

import os
import time
import math
from fastapi import FastAPI, HTTPException, Depends, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi_plugin import Auth0FastAPI
from pydantic import BaseModel

auth = Auth0FastAPI(domain=os.environ["AUTH0_DOMAIN"], audience=os.environ["AUTH0_AUDIENCE"], dpop_enabled=False)
validate_token = auth.require_auth()

async def learner_access(request: Request):
    try:
        claims = await validate_token(request)
    except HTTPException as exc:
        if exc.status_code in (400, 401):
            raise HTTPException(401, "Authentication required", headers={"WWW-Authenticate": "Bearer"}) from None
        raise HTTPException(503, "Authentication temporarily unavailable") from None
    now = time.time()
    def numeric(value):
        return type(value) in (int, float) and math.isfinite(value)
    if (not isinstance(claims.get("sub"), str) or not claims["sub"]
        or not numeric(claims.get("iat")) or claims["iat"] > now + 30
        or not numeric(claims.get("exp")) or claims["exp"] <= now
        or ("nbf" in claims and (not numeric(claims["nbf"]) or claims["nbf"] > now))):
        raise HTTPException(401, "Invalid token claims", headers={"WWW-Authenticate": "Bearer"})
    if claims.get("azp") != os.environ["AUTH0_CLIENT_ID"]:
        raise HTTPException(401, "Invalid client", headers={"WWW-Authenticate": "Bearer"})
    permissions = claims.get("permissions")
    if not isinstance(permissions, list) or "learner:access" not in permissions:
        raise HTTPException(403, "Learner access required")
    return claims

app = FastAPI(title="SWE Learning API", version="0.2.0", docs_url=None, redoc_url=None, openapi_url=None)
app.add_middleware(CORSMiddleware,
    allow_origins=[os.getenv("FRONTEND_ORIGIN", "http://localhost:3000")],
    allow_methods=["GET"], allow_headers=["Authorization", "Content-Type"])

@app.middleware("http")
async def private_responses(request, call_next):
    response = await call_next(request)
    response.headers["Cache-Control"] = "private, no-store"
    response.headers["X-Content-Type-Options"] = "nosniff"
    return response

class Lesson(BaseModel):
    id: str
    title: str

LESSONS = [
    Lesson(id="backend-01", title="Follow a browser request"),
    Lesson(id="backend-02", title="Deploy an API from GitHub"),
]

@app.get("/health")
def health():
    return {"status": "ok", "version": os.getenv("APP_VERSION", "local")}

@app.get("/api/v1/lessons", response_model=list[Lesson], dependencies=[Depends(learner_access)])
def lessons():
    return LESSONS

@app.get("/api/v1/lessons/{lesson_id}", response_model=Lesson, dependencies=[Depends(learner_access)])
def lesson(lesson_id: str):
    for item in LESSONS:
        if item.id == lesson_id:
            return item
    raise HTTPException(status_code=404, detail="Lesson not found")

