from pathlib import Path

from fastapi import APIRouter, Form, HTTPException, Request
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from itsdangerous import BadSignature, SignatureExpired
from pydantic import EmailStr

from app.config import get_settings
from app.db import log_download, upsert_lead
from app.security import (
    create_download_token,
    is_honeypot_filled,
    verify_download_token,
)

router = APIRouter()

_TEMPLATES_DIR = Path(__file__).parent / "templates"
templates = Jinja2Templates(directory=str(_TEMPLATES_DIR))

DOWNLOADS = [
    {
        "filename": "taller-wox-tecnico.zip",
        "icon": "code",
        "title": "Material técnico",
        "description": "Specs OpenAPI, configs y artefactos para importar a watsonx Orchestrate.",
    },
    {
        "filename": "taller-wox-funcional.zip",
        "icon": "book",
        "title": "Material funcional",
        "description": "Manual paso a paso del bootcamp y deck de slides.",
    },
]
ALLOWED_FILENAMES = {d["filename"] for d in DOWNLOADS}


@router.get("/", response_class=HTMLResponse)
def landing(request: Request, error: str | None = None):
    error_msg = None
    if error == "token-invalido":
        error_msg = "El link expiró o es inválido. Regístrate de nuevo para descargar el material."
    return templates.TemplateResponse(
        "index.html",
        {"request": request, "error": error_msg},
    )


@router.post("/register")
def register(
    request: Request,
    nombre: str = Form(..., min_length=2, max_length=80),
    email: EmailStr = Form(...),
    empresa: str = Form(..., min_length=2, max_length=100),
    consentimiento: str = Form(...),
    website: str | None = Form(default=""),
):
    if consentimiento != "on":
        raise HTTPException(status_code=400, detail="Consentimiento requerido")

    if is_honeypot_filled(website):
        fake_token = create_download_token(email="honeypot@discarded.local", nombre="x")
        return RedirectResponse(url=f"/descargas?token={fake_token}", status_code=303)

    client_ip = request.client.host if request.client else None
    user_agent = request.headers.get("user-agent")

    upsert_lead(
        nombre=nombre,
        email=str(email),
        empresa=empresa,
        ip=client_ip,
        user_agent=user_agent,
        consent=True,
    )

    token = create_download_token(email=str(email), nombre=nombre)
    return RedirectResponse(url=f"/descargas?token={token}", status_code=303)


@router.get("/descargas", response_class=HTMLResponse)
def descargas(request: Request, token: str | None = None):
    if not token:
        return RedirectResponse(url="/?error=token-invalido", status_code=307)
    try:
        data = verify_download_token(token)
    except (SignatureExpired, BadSignature):
        return RedirectResponse(url="/?error=token-invalido", status_code=307)

    settings = get_settings()
    material_dir = Path(settings.material_dir)
    downloads_view = []
    for d in DOWNLOADS:
        path = material_dir / d["filename"]
        downloads_view.append({
            **d,
            "available": path.exists(),
            "size_mb": round(path.stat().st_size / (1024 * 1024), 1) if path.exists() else 0,
        })

    return templates.TemplateResponse(
        "descargas.html",
        {
            "request": request,
            "nombre": data.get("nombre", "amig@"),
            "token": token,
            "downloads": downloads_view,
        },
    )


@router.get("/download/{filename}")
def download(request: Request, filename: str, token: str | None = None):
    if not token:
        raise HTTPException(status_code=401, detail="Missing token")
    try:
        data = verify_download_token(token)
    except (SignatureExpired, BadSignature):
        raise HTTPException(status_code=401, detail="Invalid or expired token")

    if filename not in ALLOWED_FILENAMES:
        raise HTTPException(status_code=404, detail="File not found")

    path = Path(get_settings().material_dir) / filename
    if not path.exists():
        raise HTTPException(status_code=404, detail="File not available yet")

    client_ip = request.client.host if request.client else None
    log_download(lead_email=data["email"], filename=filename, ip=client_ip)

    return FileResponse(
        path=str(path),
        filename=filename,
        media_type="application/zip",
    )
