import { MigrationInterface, QueryRunner } from "typeorm";

/**
 * Extend `freight.invoices` into the billing record of record for every source
 * (booking, demurrage, warehouse fees, …) so warehouse fee invoices can be
 * centralized onto it instead of the parallel `warehouse_fee_invoices` table.
 *
 * Adds money tracking that supports partial payment (`subtotal/tax/paid/balance`),
 * a `paid_at` stamp, a `payments` jsonb ledger, and the `ISSUED` / `PARTIALLY_PAID`
 * statuses the warehouse flow uses.
 *
 * Matches billing/entities/invoice.entity.ts. All columns are additive with
 * defaults, so existing booking/demurrage rows are unaffected.
 */
export class ExtendInvoicesForPartialPayment1828000000000
  implements MigrationInterface
{
  name = "ExtendInvoicesForPartialPayment1828000000000";

  public async up(queryRunner: QueryRunner): Promise<void> {
    // New statuses. ADD VALUE is non-transactional-value-safe on PG 12+ as long
    // as the value is not referenced in the same transaction (it is not here).
    await queryRunner.query(
      `ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'ISSUED' BEFORE 'PENDING';`,
    );
    await queryRunner.query(
      `ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'PARTIALLY_PAID' BEFORE 'PAID';`,
    );

    await queryRunner.query(`
      ALTER TABLE freight.invoices
        ADD COLUMN IF NOT EXISTS subtotal_amount numeric(14, 2) NOT NULL DEFAULT 0,
        ADD COLUMN IF NOT EXISTS tax_amount numeric(14, 2) NOT NULL DEFAULT 0,
        ADD COLUMN IF NOT EXISTS paid_amount numeric(14, 2) NOT NULL DEFAULT 0,
        ADD COLUMN IF NOT EXISTS balance_amount numeric(14, 2) NOT NULL DEFAULT 0,
        ADD COLUMN IF NOT EXISTS paid_at timestamptz,
        ADD COLUMN IF NOT EXISTS payments jsonb NOT NULL DEFAULT '[]';
    `);

    // Backfill existing rows: subtotal mirrors the total (no tax was modeled),
    // the outstanding balance is the full total for unpaid invoices.
    await queryRunner.query(`
      UPDATE freight.invoices
         SET subtotal_amount = total_amount,
             balance_amount  = total_amount;
    `);

    // Already-settled invoices: fully paid, zero balance, stamped from updated_at.
    await queryRunner.query(`
      UPDATE freight.invoices
         SET paid_amount    = total_amount,
             balance_amount = 0,
             paid_at        = updated_at
       WHERE status = 'PAID';
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      ALTER TABLE freight.invoices
        DROP COLUMN IF EXISTS payments,
        DROP COLUMN IF EXISTS paid_at,
        DROP COLUMN IF EXISTS balance_amount,
        DROP COLUMN IF EXISTS paid_amount,
        DROP COLUMN IF EXISTS tax_amount,
        DROP COLUMN IF EXISTS subtotal_amount;
    `);
    // Postgres cannot drop individual enum values; ISSUED / PARTIALLY_PAID are
    // left on freight.invoices_status_enum (harmless, unused after down).
  }
}
