import { Entity, Column, Index, ManyToOne, JoinColumn, Check } from 'typeorm';
import { BaseEntity } from '../database/base.entity';
import { BookingHotelItemEntity } from './booking-hotel-item.entity';

/**
 * A single "room booking" period on a booking hotel stay.
 *
 * A stay can carry N periods so ops can express mixed room types on
 * the same nights (2 Deluxe + 1 Royal on nights 1..3), a mid-stay
 * room-type upgrade (Deluxe nights 1-2 → Suite night 3), or a
 * partial-nights split (Deluxe nights 1-2 at rate X, Deluxe nights
 * 3-5 at rate Y). Nights are 0-based indexes into the stay's
 * check_in..check_out window and MAY overlap across siblings.
 *
 * Line total (computed in service, not stored):
 *     rate_per_night × nights.length × num_rooms
 */
@Entity('booking_hotel_periods')
@Index('ix_booking_hotel_periods_tenant_item', ['tenant_id', 'hotel_item_id'], {
  where: '"is_deleted" = false',
})
// Deterministic display order — two live rows can't share the same
// sort_order under the same stay. Prevents the "list flickers on
// reload" bug when TypeORM has to tie-break by id.
@Index(
  'ux_booking_hotel_periods_item_sort',
  ['hotel_item_id', 'sort_order'],
  { unique: true, where: '"is_deleted" = false' },
)
@Check('ck_booking_hotel_periods_num_rooms', '"num_rooms" >= 1')
@Check('ck_booking_hotel_periods_pax_per_room', '"pax_per_room" >= 1')
@Check('ck_booking_hotel_periods_rate_non_neg', '"rate_per_night" >= 0')
// Absolute DB-level bound on the nights array — no night index can
// be negative or exceed 99. Application layer additionally enforces
// "within parent stay's window" via assertNightsInRange — see
// common/hotel/hotel-validation.ts.
@Check(
  'ck_booking_hotel_periods_nights_range',
  `"nights" = '{}'::integer[] OR (0 <= ALL("nights") AND 99 >= ALL("nights"))`,
)
export class BookingHotelPeriodEntity extends BaseEntity {
  @ManyToOne(() => BookingHotelItemEntity, (h) => h.periods, {
    onDelete: 'CASCADE',
  })
  @JoinColumn({ name: 'hotel_item_id' })
  hotel_item: BookingHotelItemEntity;

  @Column({ type: 'uuid' })
  hotel_item_id: string;

  /** Stable display order — lowest first. */
  @Column({ type: 'int', default: 0 })
  sort_order: number;

  /** 0-based night indexes covered by this period. May overlap with
   *  sibling periods for mixed room types on the same nights. */
  @Column({ type: 'integer', array: true, default: () => "'{}'::integer[]" })
  nights: number[];

  @Column({ type: 'varchar', length: 100, default: '' })
  room_type: string;

  @Column({ type: 'varchar', length: 100, default: '' })
  meal_plan: string;

  @Column({ type: 'int', default: 1 })
  num_rooms: number;

  @Column({ type: 'int', default: 2 })
  pax_per_room: number;

  @Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
  rate_per_night: number;
}
