from datetime import datetime
from pathlib import Path

from fastapi import Depends, FastAPI, HTTPException, Query, Request
from fastapi.responses import HTMLResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session

from app.anviz_client import AnvizError
from app.database import Base, engine, get_db
from app import services
from app.devices import load_relojes

BASE_DIR = Path(__file__).resolve().parent
app = FastAPI(title="Reloj Farallón - Marcaciones Anviz")
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static")


@app.on_event("startup")
def startup():
    Base.metadata.create_all(bind=engine)
    load_relojes()


@app.get("/", response_class=HTMLResponse)
def index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})


@app.get("/api/relojes")
def api_relojes():
    return {"relojes": services.list_relojes_config()}


@app.get("/api/status")
def api_status(reloj_id: str | None = None):
    try:
        return services.device_status(reloj_id)
    except KeyError as exc:
        raise HTTPException(404, str(exc)) from exc
    except FileNotFoundError as exc:
        raise HTTPException(500, str(exc)) from exc


@app.post("/api/sync")
def api_sync(
    reloj_id: str | None = Query(None, description="Omitir para sincronizar los 3 relojes"),
    db: Session = Depends(get_db),
):
    try:
        return services.sync_from_device(db, reloj_id)
    except KeyError as exc:
        raise HTTPException(404, str(exc)) from exc
    except AnvizError as exc:
        raise HTTPException(502, detail=str(exc)) from exc


@app.get("/api/marcaciones")
def api_marcaciones(
    desde: str | None = Query(None, description="YYYY-MM-DD"),
    hasta: str | None = Query(None, description="YYYY-MM-DD"),
    user_code: int | None = None,
    reloj_id: str | None = None,
    limit: int = Query(100, ge=1, le=1000),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
):
    d_desde = _parse_date(desde, end_of_day=False) if desde else None
    d_hasta = _parse_date(hasta, end_of_day=True) if hasta else None
    rows, total = services.list_marcaciones(
        db, d_desde, d_hasta, user_code, reloj_id, limit, offset
    )
    return {
        "total": total,
        "items": [
            {
                "id": r.id,
                "reloj_id": r.reloj_id,
                "reloj_name": r.reloj_name,
                "user_code": r.user_code,
                "marcacion_at": r.marcacion_at.isoformat(sep=" "),
                "type_label": r.type_label,
                "backup_label": r.backup_label,
                "work_type": r.work_type,
            }
            for r in rows
        ],
    }


@app.get("/api/export/excel")
def api_export_excel(
    desde: str = Query(..., description="YYYY-MM-DD"),
    hasta: str = Query(..., description="YYYY-MM-DD"),
    reloj_id: str | None = None,
    db: Session = Depends(get_db),
):
    d_desde = _parse_date(desde, end_of_day=False)
    d_hasta = _parse_date(hasta, end_of_day=True)
    if d_desde > d_hasta:
        raise HTTPException(400, "La fecha inicial no puede ser mayor que la final")

    buf = services.export_excel(db, d_desde, d_hasta, reloj_id)
    suffix = f"_{reloj_id}" if reloj_id else ""
    filename = f"marcaciones{suffix}_{desde}_{hasta}.xlsx"
    return StreamingResponse(
        buf,
        media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


def _parse_date(value: str, end_of_day: bool) -> datetime:
    try:
        dt = datetime.strptime(value, "%Y-%m-%d")
    except ValueError as exc:
        raise HTTPException(400, "Formato de fecha inválido. Use YYYY-MM-DD") from exc
    if end_of_day:
        return dt.replace(hour=23, minute=59, second=59)
    return dt.replace(hour=0, minute=0, second=0)
