"""Contrataciones: crear un pedido, listarlos y cambiar su estado."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import or_, select
from sqlalchemy.orm import Session

from app import models
from app.catalog import VALID_SLUGS
from app.core import security
from app.core.database import get_db
from app.schemas.booking import BookingCreateIn, BookingOut, BookingStatusIn
from app.services.geo import point

router = APIRouter(prefix="/bookings", tags=["bookings"])

VALID_STATUS = {"accepted", "rejected", "completed", "cancelled"}


@router.post("", response_model=BookingOut, status_code=status.HTTP_201_CREATED)
def create_booking(
    data: BookingCreateIn,
    db: Session = Depends(get_db),
    current: models.User = Depends(security.get_current_user),
):
    musician = db.get(models.MusicianProfile, data.musician_id)
    if not musician:
        raise HTTPException(status.HTTP_404_NOT_FOUND, "Músico no encontrado")
    if data.service_type not in VALID_SLUGS:
        raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, "Tipo de servicio inválido")
    if data.mode == "scheduled" and data.scheduled_at is None:
        raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, "Falta la fecha programada")

    booking = models.Booking(
        client_id=current.id,
        musician_id=musician.id,
        service_type=data.service_type,
        mode=data.mode,
        scheduled_at=data.scheduled_at,
        address=data.address,
        notes=data.notes,
        price=musician.base_price,
        currency=musician.currency,
        location=point(data.lat, data.lng) if data.lat is not None and data.lng is not None else None,
    )
    db.add(booking)
    db.commit()
    db.refresh(booking)
    return BookingOut.model_validate(booking)


@router.get("", response_model=list[BookingOut])
def my_bookings(
    db: Session = Depends(get_db),
    current: models.User = Depends(security.get_current_user),
):
    """Pedidos donde soy cliente, o el músico contratado."""
    my_musician_ids = select(models.MusicianProfile.id).where(models.MusicianProfile.user_id == current.id)
    stmt = (
        select(models.Booking)
        .where(or_(models.Booking.client_id == current.id, models.Booking.musician_id.in_(my_musician_ids)))
        .order_by(models.Booking.created_at.desc())
    )
    return [BookingOut.model_validate(b) for b in db.scalars(stmt).all()]


@router.patch("/{booking_id}/status", response_model=BookingOut)
def update_status(
    booking_id: int,
    data: BookingStatusIn,
    db: Session = Depends(get_db),
    current: models.User = Depends(security.get_current_user),
):
    if data.status not in VALID_STATUS:
        raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, "Estado inválido")

    booking = db.get(models.Booking, booking_id)
    if not booking:
        raise HTTPException(status.HTTP_404_NOT_FOUND, "Pedido no encontrado")

    # El músico dueño del perfil o el cliente pueden cambiar el estado.
    musician = db.get(models.MusicianProfile, booking.musician_id)
    is_owner_musician = musician is not None and musician.user_id == current.id
    if booking.client_id != current.id and not is_owner_musician:
        raise HTTPException(status.HTTP_403_FORBIDDEN, "No podés modificar este pedido")

    booking.status = data.status
    db.commit()
    db.refresh(booking)
    return BookingOut.model_validate(booking)
