from __future__ import annotations

from pathlib import Path

from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from starlette.middleware.trustedhost import TrustedHostMiddleware

from .config import settings
from .data import (
    AWARD_AREAS,
    EVENT,
    MODULES,
    PARTNER_CATEGORIES,
    SCHEDULE,
    SPONSOR_CATEGORIES,
    STATS,
    get_module_by_slug,
)
from .security import (
    SecurityHeadersMiddleware,
    SimpleRateLimitMiddleware,
    build_registration_interest,
    create_csrf_token,
    save_registration_interest,
    validate_csrf_token,
)

app = FastAPI(
    title="BCS ICT Fest 2026 Website",
    description="Secure FastAPI website for BCS ICT Fest 2026.",
    version="1.0.0",
    docs_url=None,
    redoc_url=None,
    openapi_url=None,
)

app.add_middleware(TrustedHostMiddleware, allowed_hosts=list(settings.allowed_hosts))
app.add_middleware(SimpleRateLimitMiddleware, limit_per_minute=settings.rate_limit_per_minute)
app.add_middleware(SecurityHeadersMiddleware)

APP_DIR = Path(__file__).resolve().parent
app.mount("/static", StaticFiles(directory=APP_DIR / "static"), name="static")
templates = Jinja2Templates(directory=APP_DIR / "templates")


def selected_theme(request: Request) -> str:
    theme = request.cookies.get("theme", "hacker")
    return "light" if theme == "light" else "hacker"


def template_context(request: Request, **extra):
    theme = selected_theme(request)
    base_template = "base_light.html" if theme == "light" else "base_hacker.html"
    context = {
        "request": request,
        "theme": theme,
        "base_template": base_template,
        "event": EVENT,
        "stats": STATS,
        "modules": MODULES,
        "sponsor_categories": SPONSOR_CATEGORIES,
        "partner_categories": PARTNER_CATEGORIES,
    }
    context.update(extra)
    return context


@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
    return templates.TemplateResponse(
        "index.html",
        template_context(request, schedule=SCHEDULE, featured_modules=MODULES[:6]),
    )


@app.get("/events", response_class=HTMLResponse)
async def events(request: Request):
    return templates.TemplateResponse("events.html", template_context(request))


@app.get("/events/{slug}", response_class=HTMLResponse)
async def event_detail(slug: str, request: Request):
    module = get_module_by_slug(slug)
    if not module:
        raise HTTPException(status_code=404, detail="Event module not found")
    return templates.TemplateResponse(
        "event_detail.html",
        template_context(request, module=module, award_areas=AWARD_AREAS if module["id"] == "M14" else []),
    )


@app.get("/schedule", response_class=HTMLResponse)
async def schedule(request: Request):
    return templates.TemplateResponse("schedule.html", template_context(request, schedule=SCHEDULE))


@app.get("/sponsors", response_class=HTMLResponse)
async def sponsors(request: Request):
    return templates.TemplateResponse("sponsors.html", template_context(request))


@app.get("/partners", response_class=HTMLResponse)
async def partners(request: Request):
    return templates.TemplateResponse("partners.html", template_context(request))


@app.get("/about", response_class=HTMLResponse)
async def about(request: Request):
    return templates.TemplateResponse("about.html", template_context(request, schedule=SCHEDULE))


@app.get("/register", response_class=HTMLResponse)
async def register_get(request: Request):
    token = create_csrf_token("register-interest")
    return templates.TemplateResponse(
        "register.html",
        template_context(request, csrf_token=token, submitted=False),
    )


@app.post("/register", response_class=HTMLResponse)
async def register_post(request: Request):
    form = await request.form()
    form_dict = {key: str(value) for key, value in form.items()}
    validate_csrf_token(form_dict.get("csrf_token", ""), "register-interest")
    interest = build_registration_interest(form_dict)
    if settings.save_registrations:
        save_registration_interest(interest)
    token = create_csrf_token("register-interest")
    return templates.TemplateResponse(
        "register.html",
        template_context(request, csrf_token=token, submitted=True, submitted_name=interest.name),
    )


@app.get("/theme/{theme_name}")
async def change_theme(theme_name: str, request: Request):
    if theme_name not in {"hacker", "light"}:
        raise HTTPException(status_code=404, detail="Theme not found")
    referer = request.headers.get("referer") or "/"
    response = RedirectResponse(referer, status_code=303)
    response.set_cookie(
        "theme",
        theme_name,
        max_age=60 * 60 * 24 * 180,
        httponly=True,
        secure=settings.secure_cookies,
        samesite="lax",
    )
    return response


@app.get("/api/events")
async def api_events():
    return {"event": EVENT, "modules": MODULES}


@app.get("/health")
async def health():
    return {"status": "ok", "app": settings.app_name}


@app.exception_handler(404)
async def not_found(request: Request, exc: HTTPException):
    return templates.TemplateResponse("errors/404.html", template_context(request), status_code=404)


@app.exception_handler(500)
async def server_error(request: Request, exc: Exception):
    return templates.TemplateResponse("errors/500.html", template_context(request), status_code=500)
