import { MigrationInterface, QueryRunner } from 'typeorm';

/**
 * §12e — supplier prepayment ledger + §12d/§12e explicit Payment Type.
 *
 * 1. Supplier prepayment reuses the existing `customer_credit_ledger`
 *    pair of tables rather than introducing a third ledger. The schema
 *    is already party-agnostic (`party_type` + `party_key`); only the
 *    CHECK constraint and the payout back-references were missing.
 *      SUPPLIER → party_key = supplier uuid, balance = money the
 *      supplier is holding on our behalf (we paid ahead of the bills).
 *
 * 2. `payment_type` records the operator's stated intent on both the
 *    collection and the payout header: BILL_TO_BILL (allocate against
 *    open invoices) vs ON_ACCOUNT (park the whole amount on the party
 *    ledger). It was previously inferred from "did they tick a row",
 *    which made a deliberate deposit look like a half-finished
 *    allocation. Existing rows are backfilled from that same
 *    inference so history keeps reading the way it did.
 *
 * 3. `supplier_payouts` gains `credit_applied` + `excess_treatment` so
 *    the payout header carries the same money-in/money-parked columns
 *    the collection header already had.
 */
export class SupplierPrepaymentAndPaymentType1786400000000 implements MigrationInterface {
  name = 'SupplierPrepaymentAndPaymentType1786400000000';

  public async up(qr: QueryRunner): Promise<void> {
    // ── 1. Credit ledger accepts SUPPLIER parties ──────────────────
    await qr.query(`
      ALTER TABLE customer_credit_ledger
        DROP CONSTRAINT IF EXISTS customer_credit_ledger_party_type_valid;
    `);
    await qr.query(`
      ALTER TABLE customer_credit_ledger
        ADD CONSTRAINT customer_credit_ledger_party_type_valid
        CHECK (party_type IN ('CUSTOMER','SOURCE','SUPPLIER'));
    `);
    await qr.query(`
      ALTER TABLE customer_credit_ledger
        ADD COLUMN IF NOT EXISTS last_payout_id uuid
          REFERENCES supplier_payouts(id);
    `);
    await qr.query(`
      ALTER TABLE customer_credit_ledger_movements
        ADD COLUMN IF NOT EXISTS payout_id uuid
          REFERENCES supplier_payouts(id) ON DELETE SET NULL;
    `);

    // ── 2. Explicit payment type on both headers ───────────────────
    await qr.query(`
      ALTER TABLE payment_collections
        ADD COLUMN IF NOT EXISTS payment_type varchar(16) NOT NULL DEFAULT 'BILL_TO_BILL';
    `);
    await qr.query(`
      ALTER TABLE payment_collections
        DROP CONSTRAINT IF EXISTS payment_collections_payment_type_valid;
    `);
    await qr.query(`
      ALTER TABLE payment_collections
        ADD CONSTRAINT payment_collections_payment_type_valid
        CHECK (payment_type IN ('BILL_TO_BILL','ON_ACCOUNT'));
    `);
    await qr.query(`
      UPDATE payment_collections
         SET payment_type = 'ON_ACCOUNT'
       WHERE COALESCE(allocated_amount, 0) <= 0.005;
    `);

    await qr.query(`
      ALTER TABLE supplier_payouts
        ADD COLUMN IF NOT EXISTS payment_type varchar(16) NOT NULL DEFAULT 'BILL_TO_BILL';
    `);
    await qr.query(`
      ALTER TABLE supplier_payouts
        DROP CONSTRAINT IF EXISTS supplier_payouts_payment_type_valid;
    `);
    await qr.query(`
      ALTER TABLE supplier_payouts
        ADD CONSTRAINT supplier_payouts_payment_type_valid
        CHECK (payment_type IN ('BILL_TO_BILL','ON_ACCOUNT'));
    `);
    await qr.query(`
      UPDATE supplier_payouts
         SET payment_type = 'ON_ACCOUNT'
       WHERE COALESCE(allocated_amount, 0) <= 0.005;
    `);

    // ── 3. Payout header money columns ─────────────────────────────
    await qr.query(`
      ALTER TABLE supplier_payouts
        ADD COLUMN IF NOT EXISTS credit_applied numeric(12,2) NOT NULL DEFAULT 0;
    `);
    await qr.query(`
      ALTER TABLE supplier_payouts
        ADD COLUMN IF NOT EXISTS excess_treatment varchar(16);
    `);
    await qr.query(`
      ALTER TABLE supplier_payouts
        DROP CONSTRAINT IF EXISTS supplier_payouts_excess_treatment_valid;
    `);
    await qr.query(`
      ALTER TABLE supplier_payouts
        ADD CONSTRAINT supplier_payouts_excess_treatment_valid
        CHECK (excess_treatment IS NULL OR excess_treatment IN ('PREPAYMENT','ADVANCE'));
    `);
    // Historical payouts recorded excess with no ledger behind it; mark
    // them ADVANCE so they keep their "tracked on the voucher only"
    // meaning and never get drawn down as if they were on the ledger.
    await qr.query(`
      UPDATE supplier_payouts
         SET excess_treatment = 'ADVANCE'
       WHERE COALESCE(excess_amount, 0) > 0.005
         AND excess_treatment IS NULL;
    `);
  }

  public async down(qr: QueryRunner): Promise<void> {
    await qr.query(`
      ALTER TABLE supplier_payouts
        DROP CONSTRAINT IF EXISTS supplier_payouts_excess_treatment_valid;
    `);
    await qr.query(`ALTER TABLE supplier_payouts DROP COLUMN IF EXISTS excess_treatment;`);
    await qr.query(`ALTER TABLE supplier_payouts DROP COLUMN IF EXISTS credit_applied;`);
    await qr.query(`
      ALTER TABLE supplier_payouts
        DROP CONSTRAINT IF EXISTS supplier_payouts_payment_type_valid;
    `);
    await qr.query(`ALTER TABLE supplier_payouts DROP COLUMN IF EXISTS payment_type;`);
    await qr.query(`
      ALTER TABLE payment_collections
        DROP CONSTRAINT IF EXISTS payment_collections_payment_type_valid;
    `);
    await qr.query(`ALTER TABLE payment_collections DROP COLUMN IF EXISTS payment_type;`);
    await qr.query(`
      ALTER TABLE customer_credit_ledger_movements DROP COLUMN IF EXISTS payout_id;
    `);
    await qr.query(`ALTER TABLE customer_credit_ledger DROP COLUMN IF EXISTS last_payout_id;`);
    // Supplier ledger rows would violate the narrowed CHECK — clear
    // them before restoring the original two-party constraint.
    await qr.query(`
      DELETE FROM customer_credit_ledger_movements
       WHERE ledger_id IN (
         SELECT id FROM customer_credit_ledger WHERE party_type = 'SUPPLIER'
       );
    `);
    await qr.query(`DELETE FROM customer_credit_ledger WHERE party_type = 'SUPPLIER';`);
    await qr.query(`
      ALTER TABLE customer_credit_ledger
        DROP CONSTRAINT IF EXISTS customer_credit_ledger_party_type_valid;
    `);
    await qr.query(`
      ALTER TABLE customer_credit_ledger
        ADD CONSTRAINT customer_credit_ledger_party_type_valid
        CHECK (party_type IN ('CUSTOMER','SOURCE'));
    `);
  }
}
