import { MigrationInterface, QueryRunner } from 'typeorm';

/**
 * Simplify the rate + weight-limit configuration model:
 *
 *  1. Drop the effective_from / effective_to validity window from both
 *     `rates` and `weight_limit_rules`. Rates are now activated purely by
 *     the approval workflow (status = LIVE) and weight limits are always
 *     active for their container + direction. No time-travel scheduling.
 *
 *  2. Enforce "one rate per pattern" with partial unique indexes so the same
 *     configuration (e.g. FIRST_MILE for a given container type) cannot be
 *     duplicated. NULL scope columns are COALESCE-normalised because Postgres
 *     treats NULLs as distinct in a plain unique index.
 *
 *  This migration is destructive on the date columns — existing effective_*
 *  values are dropped.
 */
export class SimplifyRatesAndWeightLimitRules1900000000000 implements MigrationInterface {
  name = 'SimplifyRatesAndWeightLimitRules1900000000000';

  public async up(queryRunner: QueryRunner): Promise<void> {
    // ── 1. De-duplicate existing data so the unique indexes can be created ──
    // Keep the most recently-created row per pattern, soft-delete the rest.
    await queryRunner.query(`
      WITH ranked AS (
        SELECT id,
               row_number() OVER (
                 PARTITION BY rate_type,
                              COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid),
                              COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid),
                              COALESCE(trade_direction, ''),
                              rate_unit
                 ORDER BY created_at DESC, id DESC
               ) AS rn
        FROM freight.rates
        WHERE deleted_at IS NULL AND status <> 'SUPERSEDED'
      )
      UPDATE freight.rates r
      SET deleted_at = now()
      FROM ranked
      WHERE r.id = ranked.id AND ranked.rn > 1;
    `);

    await queryRunner.query(`
      WITH ranked AS (
        SELECT id,
               row_number() OVER (
                 PARTITION BY container_type_id, trade_direction
                 ORDER BY created_at DESC, id DESC
               ) AS rn
        FROM freight.weight_limit_rules
        WHERE deleted_at IS NULL
      )
      UPDATE freight.weight_limit_rules w
      SET deleted_at = now()
      FROM ranked
      WHERE w.id = ranked.id AND ranked.rn > 1;
    `);

    // ── 2. Drop the effective-date indexes + columns ───────────────────────
    await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_rates_effective_from";`);
    await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_weight_limit_rules_effective_from";`);
    // Indexes created by TypeORM's @Index carry generated hashed names — drop
    // any index that references the effective_from column defensively.
    await queryRunner.query(`
      DO $$
      DECLARE idx record;
      BEGIN
        FOR idx IN
          SELECT indexname FROM pg_indexes
          WHERE schemaname = 'freight'
            AND tablename IN ('rates', 'weight_limit_rules')
            AND indexdef ILIKE '%effective_from%'
        LOOP
          EXECUTE format('DROP INDEX IF EXISTS freight.%I', idx.indexname);
        END LOOP;
      END $$;
    `);

    await queryRunner.query(`ALTER TABLE freight.rates DROP COLUMN IF EXISTS effective_from;`);
    await queryRunner.query(`ALTER TABLE freight.rates DROP COLUMN IF EXISTS effective_to;`);
    await queryRunner.query(`ALTER TABLE freight.weight_limit_rules DROP COLUMN IF EXISTS effective_from;`);
    await queryRunner.query(`ALTER TABLE freight.weight_limit_rules DROP COLUMN IF EXISTS effective_to;`);

    // ── 3. One-rate-per-pattern partial unique indexes ─────────────────────
    // The unit is part of the identity so a surcharge can legitimately carry two
    // rows that bill different ways (e.g. reefer PER_CONTAINER + reefer PER_TON),
    // while still blocking a true duplicate (same rateType + scope + unit).
    await queryRunner.query(`
      CREATE UNIQUE INDEX IF NOT EXISTS "UQ_rates_pattern"
      ON freight.rates (
        rate_type,
        COALESCE(container_type_id, '00000000-0000-0000-0000-000000000000'::uuid),
        COALESCE(cargo_type_id, '00000000-0000-0000-0000-000000000000'::uuid),
        COALESCE(trade_direction, ''),
        rate_unit
      )
      WHERE deleted_at IS NULL AND status <> 'SUPERSEDED';
    `);

    await queryRunner.query(`
      CREATE UNIQUE INDEX IF NOT EXISTS "UQ_weight_limit_rules_pattern"
      ON freight.weight_limit_rules (container_type_id, trade_direction)
      WHERE deleted_at IS NULL;
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_rates_pattern";`);
    await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_weight_limit_rules_pattern";`);

    await queryRunner.query(`ALTER TABLE freight.rates ADD COLUMN IF NOT EXISTS effective_from date;`);
    await queryRunner.query(`UPDATE freight.rates SET effective_from = COALESCE(effective_from, created_at::date);`);
    await queryRunner.query(`ALTER TABLE freight.rates ALTER COLUMN effective_from SET NOT NULL;`);
    await queryRunner.query(`ALTER TABLE freight.rates ADD COLUMN IF NOT EXISTS effective_to date;`);

    await queryRunner.query(`ALTER TABLE freight.weight_limit_rules ADD COLUMN IF NOT EXISTS effective_from date;`);
    await queryRunner.query(`ALTER TABLE freight.weight_limit_rules ADD COLUMN IF NOT EXISTS effective_to date;`);

    await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_rates_effective_from" ON freight.rates (effective_from);`);
    await queryRunner.query(
      `CREATE INDEX IF NOT EXISTS "IDX_weight_limit_rules_effective_from" ON freight.weight_limit_rules (effective_from);`,
    );
  }
}
