"""
Reservation model for hotel bookings.
"""
import enum
from datetime import date, datetime
from sqlalchemy import Column, String, Integer, Float, Boolean, Enum, ForeignKey, Date, DateTime, Text
from sqlalchemy.orm import relationship

from app.models.base import BaseModel


class ReservationStatus(str, enum.Enum):
    """Reservation status states."""
    PENDING = "pending"
    CONFIRMED = "confirmed"
    CHECKED_IN = "checked_in"
    CHECKED_OUT = "checked_out"
    CANCELLED = "cancelled"
    NO_SHOW = "no_show"


class ReservationSource(str, enum.Enum):
    """Booking source."""
    DIRECT = "direct"
    WEBSITE = "website"
    PHONE = "phone"
    EMAIL = "email"
    OTA = "ota"
    AGENCY = "agency"
    CORPORATE = "corporate"
    WALK_IN = "walk_in"


class Reservation(BaseModel):
    """
    Hotel room reservation.

    Attributes:
        client_id: Guest making the reservation
        room_id: Reserved room
        check_in_date: Check-in date
        check_out_date: Check-out date
        actual_check_in: Actual check-in datetime
        actual_check_out: Actual check-out datetime
        status: Reservation status
        source: Booking source
        adults: Number of adults
        children: Number of children
        rate_per_night: Agreed rate per night
        total_price: Total accommodation price
        deposit_amount: Deposit amount paid
        special_requests: Guest special requests
        internal_notes: Internal notes
        confirmation_number: Unique confirmation number
        group_id: Group reservation ID (for linked bookings)
    """
    __tablename__ = "reservations"

    # References
    client_id = Column(
        Integer,
        ForeignKey("clients.id", ondelete="RESTRICT"),
        nullable=False,
        index=True
    )
    room_id = Column(
        Integer,
        ForeignKey("rooms.id", ondelete="RESTRICT"),
        nullable=False,
        index=True
    )

    # Dates
    check_in_date = Column(Date, nullable=False, index=True)
    check_out_date = Column(Date, nullable=False, index=True)
    actual_check_in = Column(DateTime, nullable=True)
    actual_check_out = Column(DateTime, nullable=True)

    # Status
    status = Column(
        Enum(ReservationStatus),
        default=ReservationStatus.PENDING,
        nullable=False,
        index=True
    )
    source = Column(
        Enum(ReservationSource),
        default=ReservationSource.DIRECT,
        nullable=False
    )

    # Occupancy
    adults = Column(Integer, default=1, nullable=False)
    children = Column(Integer, default=0, nullable=False)

    # Pricing
    rate_per_night = Column(Float, nullable=False)
    total_price = Column(Float, nullable=False)
    deposit_amount = Column(Float, default=0.0, nullable=False)
    currency = Column(String(3), default="XOF", nullable=False)

    # Notes
    special_requests = Column(Text, nullable=True)
    internal_notes = Column(Text, nullable=True)

    # Identification
    confirmation_number = Column(String(50), unique=True, nullable=False, index=True)
    group_id = Column(String(50), nullable=True, index=True)

    # Relationships
    client = relationship("Client", back_populates="reservations")
    room = relationship("Room", back_populates="reservations")
    folio = relationship(
        "Folio",
        back_populates="reservation",
        uselist=False,
        cascade="all, delete-orphan"
    )
    notifications = relationship("Notification", back_populates="reservation")

    @property
    def nights(self) -> int:
        """Calculate number of nights."""
        if self.check_in_date and self.check_out_date:
            return (self.check_out_date - self.check_in_date).days
        return 0

    @property
    def total_guests(self) -> int:
        """Total number of guests."""
        return self.adults + self.children

    @property
    def is_active(self) -> bool:
        """Check if reservation is active (not cancelled/no-show)."""
        return self.status not in [
            ReservationStatus.CANCELLED,
            ReservationStatus.NO_SHOW,
            ReservationStatus.CHECKED_OUT
        ]

    def __repr__(self) -> str:
        return f"<Reservation {self.confirmation_number}>"
