import { type MigrationInterface, type QueryRunner } from 'typeorm';

/**
 * Booking Settlement Master — two-tier settlement model.
 *
 * Stakeholder decision (2026-06-06): each booking gets a MASTER row per
 * party (customer-side + supplier-side, supplier-id-scoped); the
 * existing `payment_settlements` rows become CHILDREN that link up via
 * `master_id`. Adds:
 *
 *   1. New table `booking_settlement_masters` — rolled-up state per
 *      (booking × party × supplier_id). Carries the parent status:
 *
 *        PENDING     — no money has moved on any child
 *        PARTIAL     — some children settled, some still owe
 *        COMPLETED   — every child SETTLED
 *        HOLD        — Admin manually paused (no auto-deltas while held)
 *        REFUND_DUE  — at least one REFUND child is unsettled (wins
 *                      over PARTIAL/COMPLETED so finance sees the
 *                      money-out flag)
 *
 *      Service-layer code maintains the rollup fields (`total_expected`,
 *      `total_received`, `last_activity_at`) after every child write.
 *
 *   2. New column `payment_settlements.master_id` — FK back to the
 *      master. Required for every new settlement created post-migration.
 *
 *   3. Partial unique index — one active master per
 *      (tenant, booking, party, supplier_id) where is_deleted = false.
 *      The supplier_id slot makes (CUSTOMER) and per-supplier
 *      SUPPLIER-side masters coexist cleanly:
 *
 *        (booking-X, CUSTOMER, NULL)          ← single customer master
 *        (booking-X, SUPPLIER, supplier-A)    ← payable to Ola
 *        (booking-X, SUPPLIER, supplier-B)    ← payable to Bird taxis
 *
 *   4. Wipe of existing transactional data — per stakeholder spec
 *      ("start fresh from new bookings"). Removes payments + settlements
 *      + bookings + queries + audit_logs + notifications.
 *      Masters preserved (destinations, hotels, suppliers, vehicles,
 *      transport_pricing, seasons, etc.). Run AFTER the schema changes
 *      so the new master/child wiring is in place before any first save.
 */
export class BookingSettlementMaster1780200000000 implements MigrationInterface {
  async up(qr: QueryRunner): Promise<void> {
    // ── 1. Master table ────────────────────────────────────────────────
    await qr.query(`
      CREATE TABLE IF NOT EXISTS booking_settlement_masters (
        id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        tenant_id           UUID NOT NULL,
        booking_id          UUID NOT NULL REFERENCES bookings(id) ON DELETE CASCADE,
        party_type          VARCHAR(20) NOT NULL,
        supplier_id         UUID REFERENCES suppliers(id) ON DELETE SET NULL,
        currency_id         UUID NOT NULL REFERENCES currencies(id),
        status              VARCHAR(20) NOT NULL DEFAULT 'PENDING',
        total_expected      NUMERIC(12,2) NOT NULL DEFAULT 0,
        total_received      NUMERIC(12,2) NOT NULL DEFAULT 0,
        last_activity_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        hold_reason         TEXT,
        hold_set_by         UUID,
        hold_set_at         TIMESTAMPTZ,
        is_deleted          BOOLEAN NOT NULL DEFAULT FALSE,
        created_by          UUID,
        updated_by          UUID,
        created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        CONSTRAINT chk_master_party_type
          CHECK (party_type IN ('CUSTOMER', 'SUPPLIER')),
        CONSTRAINT chk_master_status
          CHECK (status IN ('PENDING', 'PARTIAL', 'COMPLETED', 'HOLD', 'REFUND_DUE')),
        CONSTRAINT chk_master_supplier_only_when_supplier_party
          CHECK (
            (party_type = 'SUPPLIER' AND supplier_id IS NOT NULL)
            OR
            (party_type = 'CUSTOMER' AND supplier_id IS NULL)
          ),
        CONSTRAINT chk_master_hold_reason_when_hold
          CHECK (status <> 'HOLD' OR hold_reason IS NOT NULL)
      );
    `);

    // Partial unique index — coalesce NULL supplier_id to a sentinel
    // (zero UUID) so the unique applies cleanly to CUSTOMER rows too.
    await qr.query(`
      CREATE UNIQUE INDEX IF NOT EXISTS uq_booking_settlement_master_active
        ON booking_settlement_masters (
          tenant_id, booking_id, party_type,
          COALESCE(supplier_id, '00000000-0000-0000-0000-000000000000'::uuid)
        )
        WHERE is_deleted = false;
    `);

    // List-page filtering hot path: by tenant + party + status with
    // recency sort on last_activity_at.
    await qr.query(`
      CREATE INDEX IF NOT EXISTS idx_master_tenant_party_status
        ON booking_settlement_masters (tenant_id, party_type, status, last_activity_at DESC)
        WHERE is_deleted = false;
    `);

    // Booking-detail timeline lookup.
    await qr.query(`
      CREATE INDEX IF NOT EXISTS idx_master_tenant_booking
        ON booking_settlement_masters (tenant_id, booking_id)
        WHERE is_deleted = false;
    `);

    // ── 2. Child → master FK ───────────────────────────────────────────
    await qr.query(`
      ALTER TABLE payment_settlements
        ADD COLUMN IF NOT EXISTS master_id
          UUID REFERENCES booking_settlement_masters(id) ON DELETE CASCADE;
    `);
    // Index for the recompute-master query path.
    await qr.query(`
      CREATE INDEX IF NOT EXISTS idx_settlement_master
        ON payment_settlements (master_id)
        WHERE is_deleted = false;
    `);

    // ── 3. Wipe transactional data (stakeholder: start fresh) ─────────
    // Order: child → parent so FKs are satisfied. Masters preserved
    // (destinations, hotels, suppliers, vehicles, pricing, seasons,
    // tenant_settings, users, roles, etc.) — same list as
    // scripts/wipe-transactional.sql.
    await qr.query(`DELETE FROM settlement_payments;`);
    await qr.query(`DELETE FROM payment_settlements;`);
    await qr.query(`DELETE FROM settlement_receipt_sequences;`);
    await qr.query(`DELETE FROM booking_change_requests;`);
    await qr.query(`DELETE FROM booking_flight_details;`);
    await qr.query(`DELETE FROM booking_transport_items;`);
    await qr.query(`DELETE FROM booking_activity_items;`);
    await qr.query(`DELETE FROM booking_special_items;`);
    await qr.query(`DELETE FROM booking_hotel_items;`);
    await qr.query(`DELETE FROM bookings;`);
    await qr.query(`DELETE FROM query_quote_transports;`);
    await qr.query(`DELETE FROM query_quote_activities;`);
    await qr.query(`DELETE FROM query_quote_hotels;`);
    await qr.query(`DELETE FROM query_quote_specials;`);
    await qr.query(`DELETE FROM query_quotes;`);
    await qr.query(`DELETE FROM queries;`);
    await qr.query(`DELETE FROM notifications;`);
    await qr.query(`DELETE FROM audit_logs;`);
  }

  async down(qr: QueryRunner): Promise<void> {
    await qr.query(`DROP INDEX IF EXISTS idx_settlement_master;`);
    await qr.query(`ALTER TABLE payment_settlements DROP COLUMN IF EXISTS master_id;`);

    await qr.query(`DROP INDEX IF EXISTS idx_master_tenant_booking;`);
    await qr.query(`DROP INDEX IF EXISTS idx_master_tenant_party_status;`);
    await qr.query(`DROP INDEX IF EXISTS uq_booking_settlement_master_active;`);
    await qr.query(`DROP TABLE IF EXISTS booking_settlement_masters;`);
  }
}
