import enum
from datetime import date, datetime, time

from sqlalchemy import Date, DateTime, Enum, ForeignKey, Integer, String, Text, Time, func
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.core.database import Base


class ReservationStatus(str, enum.Enum):
    pending = "pending"
    confirmed = "confirmed"
    seated = "seated"
    completed = "completed"
    cancelled = "cancelled"
    no_show = "no_show"


class ReservationSource(str, enum.Enum):
    manual = "manual"
    whatsapp = "whatsapp"
    web = "web"


reservation_status_enum = Enum(ReservationStatus, name="reservation_status")
reservation_source_enum = Enum(ReservationSource, name="reservation_source")


class Reservation(Base):
    __tablename__ = "reservations"

    id: Mapped[int] = mapped_column(primary_key=True, index=True)
    venue_id: Mapped[int] = mapped_column(ForeignKey("venues.id"), nullable=False, index=True)
    customer_id: Mapped[int] = mapped_column(ForeignKey("customers.id"), nullable=False, index=True)
    reservation_date: Mapped[date] = mapped_column(Date, nullable=False, index=True)
    start_time: Mapped[time] = mapped_column(Time, nullable=False)
    duration_minutes: Mapped[int] = mapped_column(Integer, nullable=False)
    guests: Mapped[int] = mapped_column(Integer, nullable=False)
    status: Mapped[ReservationStatus] = mapped_column(reservation_status_enum, nullable=False, default=ReservationStatus.pending)
    source: Mapped[ReservationSource] = mapped_column(reservation_source_enum, nullable=False, default=ReservationSource.manual)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    area_preference: Mapped[str | None] = mapped_column(String(120), nullable=True)
    assigned_table_id: Mapped[int | None] = mapped_column(ForeignKey("tables.id"), nullable=True, index=True)
    assigned_combination_id: Mapped[int | None] = mapped_column(
        ForeignKey("table_combinations.id"),
        nullable=True,
        index=True,
    )
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
    )

    venue = relationship("Venue", back_populates="reservations")
    customer = relationship("Customer", back_populates="reservations")
    assigned_table = relationship("Table", back_populates="reservations")
    assigned_combination = relationship("TableCombination", back_populates="reservations")
    status_history = relationship(
        "ReservationStatusHistory",
        back_populates="reservation",
        cascade="all, delete-orphan",
        order_by="ReservationStatusHistory.changed_at",
    )


class ReservationStatusHistory(Base):
    __tablename__ = "reservation_status_history"

    id: Mapped[int] = mapped_column(primary_key=True, index=True)
    reservation_id: Mapped[int] = mapped_column(ForeignKey("reservations.id"), nullable=False, index=True)
    old_status: Mapped[ReservationStatus | None] = mapped_column(reservation_status_enum, nullable=True)
    new_status: Mapped[ReservationStatus] = mapped_column(reservation_status_enum, nullable=False)
    changed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)

    reservation = relationship("Reservation", back_populates="status_history")
