from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime, timezone

from database import get_db
from models.reservation import Reservation
from models.table import Table
from schemas.reservation import (
    ReservationCreate, ReservationUpdate, ReservationStatusUpdate, ReservationOut,
)
from routers.deps import get_current_user, require_manager
from models.user import User

router = APIRouter()

VALID_STATUSES = {"pending", "arrived", "cancelled", "no_show"}


def _enrich(r: Reservation) -> ReservationOut:
    out = ReservationOut.model_validate(r)
    if r.table:
        out.table_label = r.table.label or f"T{r.table.number}"
    if r.created_by:
        out.created_by_name = (
            r.created_by.full_name or r.created_by.nickname or r.created_by.username
        )
    return out


@router.post("/", response_model=ReservationOut, status_code=status.HTTP_201_CREATED)
def create_reservation(
    body: ReservationCreate,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    if body.table_id:
        if not db.query(Table).filter(Table.id == body.table_id, Table.is_active == True).first():
            raise HTTPException(status_code=400, detail="Table not found or inactive")

    r = Reservation(
        guest_name=body.guest_name,
        party_size=body.party_size,
        phone=body.phone,
        email=body.email,
        note=body.note,
        reserved_for=body.reserved_for,
        table_id=body.table_id,
        source=body.source,
        online_customer_id=body.online_customer_id,
        created_by_user_id=user.id,
        status="pending",
    )
    db.add(r)
    db.commit()
    db.refresh(r)
    return _enrich(r)


@router.get("/", response_model=List[ReservationOut])
def list_reservations(
    tab: Optional[str] = Query(None),  # "upcoming" | "history" — if omitted returns all
    date: Optional[str] = Query(None),  # ISO date string YYYY-MM-DD to filter by day
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    q = db.query(Reservation)

    if date:
        try:
            day = datetime.fromisoformat(date).date()
        except ValueError:
            raise HTTPException(status_code=400, detail="Invalid date format")
        from sqlalchemy import func
        q = q.filter(func.date(Reservation.reserved_for) == day)

    if tab == "upcoming":
        # pending + no_show (actionable), ordered soonest first
        q = q.filter(Reservation.status.in_(["pending", "no_show"]))
        q = q.order_by(Reservation.reserved_for.asc())
    elif tab == "history":
        # arrived, cancelled, plus no_show/pending that are clearly in the past
        now = datetime.now(timezone.utc)
        q = q.filter(
            (Reservation.status.in_(["arrived", "cancelled"])) |
            (
                Reservation.status.in_(["no_show", "pending"]) &
                (Reservation.reserved_for < now)
            )
        )
        q = q.order_by(Reservation.reserved_for.desc())
    else:
        q = q.order_by(Reservation.reserved_for.asc())

    reservations = q.all()
    return [_enrich(r) for r in reservations]


@router.get("/{reservation_id}", response_model=ReservationOut)
def get_reservation(
    reservation_id: int,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    r = db.query(Reservation).filter(Reservation.id == reservation_id).first()
    if not r:
        raise HTTPException(status_code=404, detail="Reservation not found")
    return _enrich(r)


@router.patch("/{reservation_id}", response_model=ReservationOut)
def update_reservation(
    reservation_id: int,
    body: ReservationUpdate,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    r = db.query(Reservation).filter(Reservation.id == reservation_id).first()
    if not r:
        raise HTTPException(status_code=404, detail="Reservation not found")

    updates = body.model_dump(exclude_none=True)

    if "table_id" in updates and updates["table_id"] is not None:
        if not db.query(Table).filter(Table.id == updates["table_id"], Table.is_active == True).first():
            raise HTTPException(status_code=400, detail="Table not found or inactive")

    if "status" in updates and updates["status"] not in VALID_STATUSES:
        raise HTTPException(status_code=400, detail=f"Invalid status: {updates['status']}")

    for field, value in updates.items():
        setattr(r, field, value)

    r.updated_at = datetime.now(timezone.utc)
    db.commit()
    db.refresh(r)
    return _enrich(r)


@router.patch("/{reservation_id}/status", response_model=ReservationOut)
def update_reservation_status(
    reservation_id: int,
    body: ReservationStatusUpdate,
    db: Session = Depends(get_db),
    user: User = Depends(get_current_user),
):
    if body.status not in VALID_STATUSES:
        raise HTTPException(status_code=400, detail=f"Invalid status: {body.status}")

    r = db.query(Reservation).filter(Reservation.id == reservation_id).first()
    if not r:
        raise HTTPException(status_code=404, detail="Reservation not found")

    r.status = body.status
    r.updated_at = datetime.now(timezone.utc)
    db.commit()
    db.refresh(r)
    return _enrich(r)


@router.delete("/{reservation_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_reservation(
    reservation_id: int,
    db: Session = Depends(get_db),
    user: User = Depends(require_manager),
):
    r = db.query(Reservation).filter(Reservation.id == reservation_id).first()
    if not r:
        raise HTTPException(status_code=404, detail="Reservation not found")
    db.delete(r)
    db.commit()
