from fastapi import APIRouter, Request, Depends, HTTPException, Form, Body, Query, Path
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from sqlalchemy.orm import Session, aliased
from typing import Optional, List, Dict, Any
import secrets
from datetime import datetime
from pydantic import BaseModel, Field

from app.database import templates
from app.models.base import get_db
from app.auth.deps import current_user, require_admin, require_docente_or_admin, require_csrf
from app.models import auth_crud, notification_crud as notif_crud
from app.models.rating import PlayerRating, ValoracionJugador
from app.models.user import User

router = APIRouter()

# --- Models ---

class RatingIn(BaseModel):
    player_id: int
    score: int
    comment: Optional[str] = None

class ValoracionItem(BaseModel):
    area: str
    subescala: str
    indicador: str
    score: int = Field(ge=1, le=5)
    observaciones: Optional[str] = None

class ValoracionJugadorIn(BaseModel):
    player_id: int
    items: List[ValoracionItem]


# --- Helpers ---

def require_docente(request: Request):
    me = current_user(request)
    if not me:
        raise HTTPException(status_code=403, detail="Se requiere rol docente.")
    try:
        role = me["role"]
    except Exception:
        role = getattr(me, "role", None)
    if role not in ("docente", "admin"):
        raise HTTPException(status_code=403, detail="Se requiere rol docente.")
    return me

def require_csrf_header(request: Request):
    token = request.headers.get("X-CSRF-Token") or request.headers.get("X-Csrf-Token") or ""
    require_csrf(request, token)


# --- Routes ---

@router.get("/valoraciones", name="valoraciones", response_class=HTMLResponse)
async def valoraciones_page(request: Request):
    me = current_user(request)
    if not me:
        return RedirectResponse(url=request.url_for("login"), status_code=303)
    role = str(me["role"]).lower() if "role" in me.keys() else ""
    if role not in ("docente", "admin"):
        return RedirectResponse(url=request.url_for("dashboard"), status_code=303)
    return templates.TemplateResponse("valoraciones.html", {"request": request, "user": me})

@router.get("/api/users/{user_id}", response_class=JSONResponse, name="api_user_detail")
async def api_user_detail(user_id: int, request: Request, db: Session = Depends(get_db)):
    me = current_user(request)
    if not me:
        return RedirectResponse(url="/login", status_code=303)
    if me["role"] not in ("docente", "admin"):
        raise HTTPException(status_code=403, detail="Solo docentes o admin")
    
    user_data = auth_crud.get_user_with_satellites(db, user_id)
    if not user_data:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    return user_data

@router.post("/api/ratings", response_class=JSONResponse, name="api_ratings_create")
async def api_ratings_create(request: Request, payload: RatingIn, db: Session = Depends(get_db)):
    me = require_docente_or_admin(request)
    player = auth_crud.get_user_by_id(db, payload.player_id)
    if not player:
        raise HTTPException(status_code=404, detail="Jugador no encontrado")
    if str(player.role).lower() != "alumno":
        raise HTTPException(status_code=400, detail="Solo se pueden valorar alumnos")
    score = int(payload.score)
    comment = (payload.comment or "").strip()
    now = datetime.utcnow().isoformat(timespec="seconds")
    
    rating = PlayerRating(
        player_id=int(payload.player_id),
        docente_id=int(me["id"]),
        score=score,
        comment=comment,
        created_at=now
    )
    db.add(rating)
    db.commit()
    return {"ok": True}

@router.get("/api/ratings", response_class=JSONResponse, name="api_ratings_list")
async def api_ratings_list(request: Request, player_id: Optional[int] = Query(None), db: Session = Depends(get_db)):
    me = require_docente_or_admin(request)
    
    Player = aliased(User)
    Docente = aliased(User)
    
    query = db.query(
        PlayerRating.id,
        PlayerRating.player_id,
        PlayerRating.docente_id,
        PlayerRating.score,
        PlayerRating.comment,
        PlayerRating.created_at,
        Player.name.label("player_name"),
        Docente.name.label("docente_name")
    ).join(Player, Player.id == PlayerRating.player_id
    ).join(Docente, Docente.id == PlayerRating.docente_id)
    
    if player_id:
        query = query.filter(PlayerRating.player_id == int(player_id))
    
    query = query.order_by(PlayerRating.id.desc())
    rows = query.all()
    
    data = [
        {
            "id": r.id, "player_id": r.player_id, "docente_id": r.docente_id,
            "score": r.score, "comment": r.comment, "created_at": r.created_at,
            "player_name": r.player_name, "docente_name": r.docente_name
        }
        for r in rows
    ]
    return data

@router.get("/api/valoraciones_jugador", response_model=list[dict])
async def api_valoraciones_jugador_list(request: Request, player_id: int = Query(...), db: Session = Depends(get_db)):
    require_docente(request)
    
    rows = db.query(
        ValoracionJugador.eval_id,
        ValoracionJugador.created_at,
        ValoracionJugador.docente_id,
        ValoracionJugador.area,
        ValoracionJugador.subescala,
        ValoracionJugador.indicador,
        ValoracionJugador.score,
        ValoracionJugador.observaciones,
        User.name.label("docente_name")
    ).join(User, User.id == ValoracionJugador.docente_id
    ).filter(ValoracionJugador.player_id == player_id
    ).order_by(
        ValoracionJugador.created_at.desc(),
        ValoracionJugador.eval_id,
        ValoracionJugador.area,
        ValoracionJugador.subescala,
        ValoracionJugador.indicador
    ).all()
    
    return [
        {
            "eval_id": r.eval_id,
            "created_at": r.created_at,
            "docente_id": r.docente_id,
            "area": r.area,
            "subescala": r.subescala,
            "indicador": r.indicador,
            "score": r.score,
            "observaciones": r.observaciones or "",
            "docente_name": r.docente_name
        }
        for r in rows
    ]

@router.post("/api/valoraciones_jugador", response_model=dict)
async def api_valoraciones_jugador_create(request: Request, payload: ValoracionJugadorIn, db: Session = Depends(get_db)):
    me = require_docente(request)
    require_csrf_header(request)
    if not payload.items:
        raise HTTPException(status_code=400, detail="Sin ítems en la evaluación.")
    eval_id = secrets.token_hex(8)
    now = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
    for it in payload.items:
        v = ValoracionJugador(
            eval_id=eval_id,
            player_id=payload.player_id,
            docente_id=int(me["id"]),
            area=it.area.strip(),
            subescala=it.subescala.strip(),
            indicador=it.indicador.strip(),
            score=int(it.score),
            observaciones=(it.observaciones or "").strip() or None,
            created_at=now
        )
        db.add(v)
    db.commit()
    return {"ok": True, "eval_id": eval_id}
