import { Entity, Column, Index, Check, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
import { BaseEntity } from '../database/base.entity';
import { BookingEntity } from './booking.entity';
import { CurrencyEntity } from './currency.entity';
import { SupplierEntity } from './supplier.entity';
import { DriverEntity } from './driver.entity';
import { ActivityEntity } from './activity.entity';
import { UserEntity } from './user.entity';
import { BookingTransportItemEntity } from './booking-transport-item.entity';
import { BookingActivityItemEntity } from './booking-activity-item.entity';
import { BookingSpecialItemEntity } from './booking-special-item.entity';
import { BookingCashCollectionBatchEntity } from './booking-cash-collection-batch.entity';

export type CashCollectedByType = 'OWN' | 'SUPPLIER';
export type CashCollectionSourceKind = 'TRANSPORT' | 'ACTIVITY' | 'SPECIAL';
export type BookingCashCollectionStatus = 'PENDING' | 'COLLECTED' | 'CANCELLED';
export type MdCashCollectionStatus = 'PENDING' | 'COLLECTED';

/**
 * Movement Dashboard — one row per itinerary line.
 *
 * expense_*  — on-ground extras (former 💰 Cash). Never hits the invoice.
 * cash_*     — amounts stamped from Settlements → Collect Payment for MD.
 */
@Entity('booking_cash_collections')
@Index('ix_bcc_tenant_booking', ['tenant_id', 'booking_id'], {
  where: '"is_deleted" = false',
})
@Index('ux_bcc_live_transport_item', ['tenant_id', 'transport_item_id'], {
  unique: true,
  where: `"is_deleted" = false AND "transport_item_id" IS NOT NULL`,
})
@Index('ux_bcc_live_activity_item', ['tenant_id', 'activity_item_id'], {
  unique: true,
  where: `"is_deleted" = false AND "activity_item_id" IS NOT NULL`,
})
@Index('ux_bcc_live_special_item', ['tenant_id', 'special_item_id'], {
  unique: true,
  where: `"is_deleted" = false AND "special_item_id" IS NOT NULL`,
})
@Check(
  'chk_bcc_expense_collected_by_type',
  `"expense_collected_by_type" IS NULL OR "expense_collected_by_type" IN ('OWN','SUPPLIER')`,
)
@Check(
  'chk_bcc_expense_status',
  `"expense_status" IS NULL OR "expense_status" IN ('PENDING','COLLECTED','CANCELLED')`,
)
@Check('chk_bcc_expense_expected_non_neg', `"expense_expected_amount" >= 0`)
@Check(
  'chk_bcc_expense_actual_non_neg',
  `"expense_actual_amount" IS NULL OR "expense_actual_amount" >= 0`,
)
@Check(
  'chk_bcc_one_line_item',
  `(
    (CASE WHEN "transport_item_id" IS NULL THEN 0 ELSE 1 END)
    + (CASE WHEN "activity_item_id" IS NULL THEN 0 ELSE 1 END)
    + (CASE WHEN "special_item_id" IS NULL THEN 0 ELSE 1 END)
    <= 1
  )`,
)
@Check(
  'chk_bcc_expense_source_kind',
  `"expense_source_kind" IS NULL OR "expense_source_kind" IN ('TRANSPORT','ACTIVITY','SPECIAL')`,
)
@Check(
  'chk_bcc_expense_party_matches_type',
  `(
    "expense_collected_by_type" IS NULL
    OR (
      "expense_collected_by_type" = 'OWN'
      AND "expense_collector_name" IS NOT NULL
      AND "expense_supplier_id" IS NULL
      AND "expense_driver_id" IS NULL
      AND "expense_activity_id" IS NULL
      AND "expense_source_kind" IS NULL
    )
    OR (
      "expense_collected_by_type" = 'SUPPLIER'
      AND "expense_collector_name" IS NULL
      AND "expense_supplier_id" IS NOT NULL
      AND "expense_driver_id" IS NOT NULL
      AND "expense_source_kind" IN ('TRANSPORT','ACTIVITY','SPECIAL')
    )
  )`,
)
@Check(
  'chk_bcc_cash_collected_by_type',
  `"cash_collected_by_type" IS NULL OR "cash_collected_by_type" IN ('OWN','SUPPLIER')`,
)
@Check(
  'chk_bcc_cash_status',
  `"cash_status" IS NULL OR "cash_status" IN ('PENDING','COLLECTED')`,
)
@Check('chk_bcc_cash_expected_non_neg', `"cash_expected_amount" >= 0`)
@Check(
  'chk_bcc_cash_actual_non_neg',
  `"cash_actual_amount" IS NULL OR "cash_actual_amount" >= 0`,
)
@Check(
  'chk_bcc_cash_source_kind',
  `"cash_source_kind" IS NULL OR "cash_source_kind" IN ('TRANSPORT','ACTIVITY','SPECIAL')`,
)
@Check(
  'chk_bcc_driver_received_route_kind',
  `"driver_received_route_kind" IS NULL OR "driver_received_route_kind" IN ('TRANSPORT','ACTIVITY','SPECIAL')`,
)
@Check(
  'chk_bcc_cash_party_matches_type',
  `(
    "cash_collected_by_type" IS NULL
    OR (
      "cash_collected_by_type" = 'OWN'
      AND "cash_collector_name" IS NOT NULL
      AND "cash_supplier_id" IS NULL
      AND "cash_driver_id" IS NULL
      AND "cash_activity_id" IS NULL
      AND "cash_source_kind" IS NULL
    )
    OR (
      "cash_collected_by_type" = 'SUPPLIER'
      AND "cash_collector_name" IS NULL
      AND "cash_supplier_id" IS NOT NULL
      AND "cash_driver_id" IS NOT NULL
      AND "cash_source_kind" IN ('TRANSPORT','ACTIVITY','SPECIAL')
    )
  )`,
)
export class BookingCashCollectionEntity extends BaseEntity {
  @ManyToOne(() => BookingEntity, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'booking_id' })
  booking: BookingEntity;

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

  @Column({ type: 'date' })
  collection_date: string;

  @ManyToOne(() => BookingTransportItemEntity, { nullable: true, onDelete: 'CASCADE' })
  @JoinColumn({ name: 'transport_item_id' })
  transport_item: BookingTransportItemEntity | null;

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

  @ManyToOne(() => BookingActivityItemEntity, { nullable: true, onDelete: 'CASCADE' })
  @JoinColumn({ name: 'activity_item_id' })
  activity_item: BookingActivityItemEntity | null;

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

  @ManyToOne(() => BookingSpecialItemEntity, { nullable: true, onDelete: 'CASCADE' })
  @JoinColumn({ name: 'special_item_id' })
  special_item: BookingSpecialItemEntity | null;

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

  @ManyToOne(() => CurrencyEntity)
  @JoinColumn({ name: 'currency_id' })
  currency: CurrencyEntity;

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

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

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

  @ManyToOne(() => SupplierEntity, { nullable: true })
  @JoinColumn({ name: 'expense_supplier_id' })
  expense_supplier: SupplierEntity | null;

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

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

  @ManyToOne(() => ActivityEntity, { nullable: true })
  @JoinColumn({ name: 'expense_activity_id' })
  expense_activity: ActivityEntity | null;

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

  @ManyToOne(() => DriverEntity, { nullable: true })
  @JoinColumn({ name: 'expense_driver_id' })
  expense_driver: DriverEntity | null;

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

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

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

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

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

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

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

  @ManyToOne(() => UserEntity, { nullable: true })
  @JoinColumn({ name: 'expense_collected_by' })
  expense_collected_by_user: UserEntity | null;

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

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

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

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

  @ManyToOne(() => SupplierEntity, { nullable: true })
  @JoinColumn({ name: 'cash_supplier_id' })
  cash_supplier: SupplierEntity | null;

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

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

  @ManyToOne(() => ActivityEntity, { nullable: true })
  @JoinColumn({ name: 'cash_activity_id' })
  cash_activity: ActivityEntity | null;

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

  @ManyToOne(() => DriverEntity, { nullable: true })
  @JoinColumn({ name: 'cash_driver_id' })
  cash_driver: DriverEntity | null;

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

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

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

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

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

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

  @ManyToOne(() => UserEntity, { nullable: true })
  @JoinColumn({ name: 'cash_collected_by' })
  cash_collected_by_user: UserEntity | null;

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

  /** When MD confirms collected — driver received cash. Booking is `booking_id`. */
  @Column({ type: 'timestamptz', nullable: true })
  driver_received_at: Date | null;

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

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

  @OneToMany(() => BookingCashCollectionBatchEntity, (b) => b.collection)
  batches: BookingCashCollectionBatchEntity[];
}
