import { Entity, Column, Index, Check, ManyToOne, OneToMany, JoinColumn } from 'typeorm';
import { BookingActivityItemSupplierEntity } from './booking-activity-item-supplier.entity';
import { BaseEntity } from '../database/base.entity';
import { BookingEntity } from './booking.entity';
import { ActivityEntity } from './activity.entity';
import { ActivityTicketEntity } from './activity-ticket.entity';
import { SupplierEntity } from './supplier.entity';

@Entity('booking_activity_items')
@Index('ix_booking_activity_items_tenant_booking', ['tenant_id', 'booking_id'], {
  where: '"is_deleted" = false',
})
@Index('ix_bai_tenant_op_status', ['tenant_id', 'op_status'], {
  where: '"is_deleted" = false',
})
@Check(
  'chk_booking_activity_items_op_status',
  `"op_status" IN ('UNPLANNED','PLANNED','HOLD','PICKED_UP','NO_SHOW','CANCELLED')`,
)
export class BookingActivityItemEntity extends BaseEntity {
  @ManyToOne(() => BookingEntity, (b) => b.activity_items, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'booking_id' })
  booking: BookingEntity;

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

  @ManyToOne(() => ActivityEntity)
  @JoinColumn({ name: 'activity_id' })
  activity: ActivityEntity;

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

  @ManyToOne(() => ActivityTicketEntity, { nullable: true })
  @JoinColumn({ name: 'ticket_id' })
  ticket: ActivityTicketEntity | null;

  @Column({ type: 'uuid', nullable: true })
  ticket_id: string | null;

  @Column({ type: 'varchar', length: 50 })
  age_group: string;

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

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

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

  @Column({ type: 'varchar', length: 100, nullable: true })
  slot: string | null;

  @Column({ type: 'date', nullable: true })
  date: string | null;

  @Column({ type: 'int', default: 0 })
  sort_order: number;

  @Column({ type: 'text', nullable: true })
  notes: string | null;

  // Per-row pax override. Null ⇒ inherit booking pax; set when one or
  // more guests skip this activity (partial cancellation, illness,
  // different-day split). Editable from Movement Chart → Planner.
  @Column({ type: 'int', nullable: true })
  adults_override: number | null;

  @Column({ type: 'int', nullable: true })
  children_override: number | null;

  /** Movement Dashboard add-on pax — guests outside the booking's party
   *  who joined this activity line. Billed as a separate customer
   *  settlement row (source MD_ADDON); the booking's pax / total are
   *  untouched. Fanned out across the line's age-group rows. */
  @Column({ type: 'int', default: 0 })
  addon_adults: number;

  @Column({ type: 'int', default: 0 })
  addon_children: number;

  /** Running total billed for the add-on pax (selling currency) — the
   *  basis for a pro-rata refund when add-ons are reduced. */
  @Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
  addon_billed_amount: number;

  // --- Supplier Assignment (Phase B — nullable for now) ---
  @ManyToOne(() => SupplierEntity, { nullable: true })
  @JoinColumn({ name: 'supplier_id' })
  supplier: SupplierEntity | null;

  @Column({ type: 'uuid', nullable: true })
  supplier_id: string | null;

  // Free-text fallbacks mirroring transport items. Used when an
  // activity's supplier isn't yet a registered master record, so ops
  // can type the name + phone inline (same pattern as transport).
  @Column({ type: 'varchar', length: 255, nullable: true })
  supplier_name_text: string | null;

  @Column({ type: 'varchar', length: 20, nullable: true })
  supplier_phone_text: string | null;

  // --- Ticket Upload (future — nullable for now) ---
  @Column({ type: 'varchar', length: 500, nullable: true })
  ticket_file_url: string | null;

  @Column({ type: 'varchar', length: 20, nullable: true })
  assignment_status: string | null;

  /** Per-line ticket lifecycle (Pending / Booked / On Hold /
   *  Cancelled / No Show). Independent of inventory batches so each
   *  booking activity can differ. Auto Booked when a ticket is
   *  uploaded/assigned; back to Pending when returned to batch. */
  @Column({ type: 'varchar', length: 20, default: 'Pending' })
  ticket_status: string;

  /** Operational lifecycle — see OpStatus enum. PLANNED → PICKED_UP
   *  (rendered as "Started" for activities) → DROPPED ("Completed").
   *  DISPATCHED doesn't apply to activities. */
  @Column({ type: 'varchar', length: 20, default: 'PLANNED' })
  op_status: string;

  @Column({ type: 'timestamp', nullable: true })
  op_status_at: Date | null;

  // ── Tax snapshot (added 2026-05-07 — see migration 1777700000000) ────
  // Re-snapshotted at booking-create from quote (Q1=C); immutable
  // on edit unless refresh_tax: true (Q2=B).
  @Column({ type: 'jsonb', nullable: true })
  tax_breakdown: Record<string, Record<string, number>> | null;

  @Column({ type: 'decimal', precision: 12, scale: 2, nullable: true })
  tax_amount: number | null;

  /**
   * Per-line ACTUAL supplier cost (per-trip TOTAL — qty already baked
   * in). Same semantic as the transport version. Populated:
   *   - at booking-create from the activity_pricing floor snapshot
   *   - by ops on the Movement Chart Planner activity rows once a
   *     supplier is assigned
   *
   * Drives the SUPPLIER REFUND amount on `recordSupplierPayable`.
   * Nullable — null means "Floor unknown, fill in when supplier picked".
   */
  @Column({ type: 'decimal', precision: 12, scale: 2, nullable: true })
  actual_supplier_cost: number | null;

  // ── Activity Cancellation / Refund (added for ops workflow) ─────────
  // cancelled_count: how many pax from this item were cancelled (0 = none)
  @Column({ type: 'int', default: 0 })
  cancelled_count: number;

  // refund_status: NONE | REFUNDED
  @Column({ type: 'varchar', length: 20, default: 'NONE' })
  refund_status: string;

  @Column({ type: 'text', nullable: true })
  cancellation_notes: string | null;

  /** Per-line customer-side slab snapshot (added in migration
   *  1781100000000). See query-quote-hotel.entity.ts for the policy. */
  @Column({ type: 'jsonb', nullable: true })
  tax_snapshot: Record<string, unknown> | null;

  /** Supplier-side slab snapshot tied to actual_supplier_cost.
   *  Movement Dashboard writes this on cost-cell save. */
  @Column({ type: 'jsonb', nullable: true })
  cost_tax_snapshot: Record<string, unknown> | null;

  /** Multi-supplier junction rows — see migration 1784000. */
  @OneToMany(
    () => BookingActivityItemSupplierEntity,
    (s) => s.activity_item,
  )
  suppliers: BookingActivityItemSupplierEntity[];
}
