"""FastAPI web interface for pace2fit."""

from __future__ import annotations

from pathlib import Path

from fastapi import FastAPI, HTTPException
from fastapi.responses import HTMLResponse, Response
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel

from pace2fit.encoder import encode
from pace2fit.parser import ParseError, parse

app = FastAPI(title="pace2fit", docs_url=None, redoc_url=None)

_STATIC_DIR = Path(__file__).parent / "static"

app.mount("/static", StaticFiles(directory=_STATIC_DIR), name="static")


class GenerateRequest(BaseModel):
    workout: str
    name: str | None = None


@app.get("/", response_class=HTMLResponse)
async def index() -> HTMLResponse:
    """Serve the single-page UI."""
    html = (_STATIC_DIR / "index.html").read_text()
    return HTMLResponse(content=html)


@app.post("/api/generate")
async def generate(req: GenerateRequest) -> Response:
    """Parse the DSL and return a .fit file download."""
    workout_str = req.workout.strip()
    if not workout_str:
        raise HTTPException(status_code=400, detail="Workout string is empty.")

    try:
        parsed = parse(workout_str, name=req.name)
    except (ParseError, ValueError) as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc

    try:
        data = encode(parsed)
    except Exception as exc:
        raise HTTPException(status_code=500, detail=f"Encoding error: {exc}") from exc

    filename = _safe_filename(req.name or workout_str)

    return Response(
        content=data,
        media_type="application/octet-stream",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


def _safe_filename(raw: str) -> str:
    """Turn an arbitrary string into a safe .fit filename."""
    cleaned = "".join(c if c.isalnum() or c in "-_ " else "_" for c in raw)
    cleaned = cleaned.strip().replace(" ", "_")[:60]
    if not cleaned:
        cleaned = "workout"
    return f"{cleaned}.fit"
