from fastapi import APIRouter, Request, Form, Depends, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from sqlalchemy.orm import Session
from urllib.parse import urlparse
from typing import List, Optional

from ..database import templates
from ..models import notification_crud as notif_crud
from ..models import auth_crud
from ..models import reservation_crud as res_crud
from ..models.base import get_db
from ..auth.deps import current_user, require_csrf

router = APIRouter()

@router.get("/notificaciones", name="notificaciones", response_class=HTMLResponse)
async def notificaciones(request: Request, user_id: int | None = None, db: Session = Depends(get_db)):
    me = current_user(request)
    if not me:
        return RedirectResponse(url="/login", status_code=303)
    target_user_id = int(me["id"])
    view_user = None
    if user_id is not None:
        try:
            user_id = int(user_id)
        except Exception:
            user_id = None
    if user_id and me["role"] in ("docente", "admin"):
            view_user = auth_crud.get_user_by_id(db, user_id)
            if view_user:
                target_user_id = int(view_user.id)
    
    inbox = notif_crud.get_notifications_for_user(db, target_user_id)
    sent = []
    if me["role"] in ("docente", "admin"):
        if view_user:
            sent = notif_crud.get_notifications_sent_by_user_to_user(db, int(me["id"]), target_user_id)
        else:
            sent = notif_crud.get_notifications_sent_by_user(db, int(me["id"]))
    students = []
    if me["role"] in ("docente", "admin"):
        students = auth_crud.get_all_students(db)
    
    notifications_json = inbox
    appointments = []
    appointments_map = {}
    appointments_json = []
    if view_user:
        # Use SQLAlchemy to get reservations
        from ..models.reservation import Reservation
        
        reservations = db.query(Reservation).filter(
            Reservation.user_id == target_user_id
        ).order_by(Reservation.date.asc(), Reservation.time.asc()).all()
        
        # Convert to dicts
        appointments = [res_crud.reservation_to_dict(r) for r in reservations]
        appointments_json = appointments
        appointments_map = {int(a["id"]): a for a in appointments}
    
    return templates.TemplateResponse(
        "notificaciones.html",
        {
            "request": request,
            "user": me,
            "view_user": auth_crud.user_to_dict(view_user) if view_user else None,
            "notifications": inbox,
            "sent_notifications": sent,
            "students": students,
            "notifications_json": notifications_json,
            "appointments": appointments,
            "appointments_json": appointments_json,
            "appointments_map": appointments_map,
        }
    )

@router.post("/notificaciones", name="create_notification")
async def create_notification(
    request: Request,
    recipient_id: int = Form(...),
    title: str = Form(...),
    body: str = Form(...),
    next_url: str | None = Form(None),
    reservation_id: int | None = Form(None),
    csrf: str | None = Form(None),
    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 pueden enviar notificaciones.")
    require_csrf(request, csrf)
    title = (title or "").strip()
    body = (body or "").strip()
    if not title or not body:
        raise HTTPException(status_code=400, detail="Título y mensaje son obligatorios.")
    try:
        recipient_id = int(recipient_id)
    except Exception:
        raise HTTPException(status_code=400, detail="Destinatario inválido.")
    
    res_id_to_save = None
    if reservation_id is not None and str(reservation_id).strip() != "":
        try:
            res_id_to_save = int(reservation_id)
            # Verify reservation ownership/validity
            res = res_crud.get_reservation_by_id(db, res_id_to_save)
            if not res:
                raise HTTPException(status_code=404, detail="Reserva no encontrada.")
            if res.user_id != recipient_id:
                 raise HTTPException(status_code=400, detail="La reserva no pertenece al alumno seleccionado.")
        except HTTPException:
            raise
        except Exception:
            raise HTTPException(status_code=400, detail="Reserva inválida.")

    # Use ORM
    notif_crud.create_notification(
        db,
        recipient_id=recipient_id,
        title=title,
        body=body,
        sender_id=int(me["id"]),
        reservation_id=res_id_to_save
    )
    
    if next_url:
        parsed = urlparse(next_url)
        if parsed.scheme == "" and parsed.netloc == "":
            return RedirectResponse(url=next_url, status_code=303)
    return RedirectResponse(url="/notificaciones", status_code=303)

@router.post("/notificaciones/eliminar", name="delete_notification")
async def delete_notification(
    request: Request,
    notification_id: int = Form(...),
    next_url: str | None = Form(None),
    target_recipient_id: int | None = Form(None),
    csrf: str | None = Form(None),
    db: Session = Depends(get_db)
):
    me = current_user(request)
    if not me:
        return RedirectResponse(url="/login", status_code=303)
    require_csrf(request, csrf)
    
    role = me["role"] if isinstance(me, dict) else getattr(me, "role", "alumno")
    
    success = notif_crud.delete_notification(
        db, 
        notification_id, 
        int(me["id"]), 
        str(role), 
        target_recipient_id=int(target_recipient_id) if target_recipient_id else None
    )
    
    if not success:
         pass
         
    if next_url:
        parsed = urlparse(next_url)
        if parsed.scheme == "" and parsed.netloc == "":
            return RedirectResponse(url=next_url, status_code=303)
    return RedirectResponse(url="/notificaciones", status_code=303)
