from typing import List
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select, or_

from app.api.deps import get_current_active_user
from app.core.db import get_session
from app.models.models import User, MentorSlot
from app.schemas.auth import SessionResponse, SessionReschedule

router = APIRouter(prefix="/sessions", tags=["sessions"])


def _build_session_response(slot: MentorSlot, db: Session) -> SessionResponse:
    mentor = db.get(User, slot.mentor_id)
    booker = db.get(User, slot.booked_by_id) if slot.booked_by_id else None
    return SessionResponse(
        id=slot.id,
        mentor_id=slot.mentor_id,
        mentor_display_name=mentor.display_name or mentor.username if mentor else None,
        start_time=slot.start_time,
        end_time=slot.end_time,
        title=slot.title,
        notes=slot.notes,
        booked_by_id=slot.booked_by_id,
        booked_by_display_name=booker.display_name or booker.username if booker else None,
    )


@router.get("", response_model=List[SessionResponse])
def my_sessions(
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_session),
):
    """Return all booked sessions where the current user is the mentor or the mentee."""
    slots = db.exec(
        select(MentorSlot)
        .where(
            MentorSlot.is_booked == True,
            or_(
                MentorSlot.mentor_id == current_user.id,
                MentorSlot.booked_by_id == current_user.id,
            ),
        )
        .order_by(MentorSlot.start_time)
    ).all()
    return [_build_session_response(s, db) for s in slots]


@router.delete("/{slot_id}", status_code=204)
def cancel_session(
    slot_id: int,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_session),
):
    """Unbook a session. Either the mentor or the mentee may cancel."""
    slot = db.get(MentorSlot, slot_id)
    if not slot or not slot.is_booked:
        raise HTTPException(status_code=404, detail="Session not found")
    is_mentor = slot.mentor_id == current_user.id
    is_mentee = slot.booked_by_id == current_user.id
    if not (is_mentor or is_mentee):
        raise HTTPException(status_code=403, detail="Not authorised to cancel this session")
    slot.is_booked = False
    slot.booked_by_id = None
    db.add(slot)
    db.commit()


@router.patch("/{slot_id}/reschedule", response_model=SessionResponse)
def reschedule_session(
    slot_id: int,
    payload: SessionReschedule,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_session),
):
    """Change a session's time. Only the mentor who owns the slot may reschedule."""
    slot = db.get(MentorSlot, slot_id)
    if not slot or not slot.is_booked:
        raise HTTPException(status_code=404, detail="Session not found")
    if slot.mentor_id != current_user.id:
        raise HTTPException(status_code=403, detail="Only the mentor can reschedule this session")
    if payload.start_time >= payload.end_time:
        raise HTTPException(status_code=400, detail="end_time must be after start_time")
    now = datetime.now(timezone.utc).replace(tzinfo=None)
    if payload.start_time < now:
        raise HTTPException(status_code=400, detail="New time cannot be in the past")
    slot.start_time = payload.start_time
    slot.end_time = payload.end_time
    db.add(slot)
    db.commit()
    db.refresh(slot)
    return _build_session_response(slot, db)
