import { MigrationInterface, QueryRunner } from "typeorm";

/**
 * Initial edr_payment schema: payment_intent, payment_webhook_event, notification_outbox.
 *
 * Enum-valued columns are varchar on purpose (values mirror the @edr/types enums) so new
 * providers/statuses never need an ALTER TYPE. uuid defaults use gen_random_uuid() (built into
 * Postgres 13+; no extension required).
 */
export class InitPaymentSchema1781136000000 implements MigrationInterface {
  name = "InitPaymentSchema1781136000000";

  public async up(queryRunner: QueryRunner): Promise<void> {
    // Defensive — bootstrap (ensure-schema) normally creates this before migrations run.
    await queryRunner.query(`CREATE SCHEMA IF NOT EXISTS "edr_payment"`);

    await queryRunner.query(`
      CREATE TABLE "edr_payment"."payment_intent" (
        "id"                     uuid        NOT NULL DEFAULT gen_random_uuid(),
        "created_at"             timestamptz NOT NULL DEFAULT now(),
        "updated_at"             timestamptz NOT NULL DEFAULT now(),
        "deleted_at"             timestamptz,
        "service"                varchar(16) NOT NULL,
        "reference_type"         varchar(16) NOT NULL,
        "reference_id"           varchar(64) NOT NULL,
        "merchant_order_id"      varchar(64) NOT NULL,
        "provider"               varchar(16) NOT NULL,
        "provider_order_id"      varchar(128),
        "provider_txn_id"        varchar(128),
        "amount_minor"           integer     NOT NULL,
        "confirmed_amount_minor" integer,
        "currency"               varchar(8)  NOT NULL,
        "status"                 varchar(24) NOT NULL DEFAULT 'REQUIRES_ACTION',
        "client_action"          jsonb,
        "failure_code"           varchar(64),
        "failure_message"        text,
        "idempotency_key"        varchar(128),
        "expires_at"             timestamptz,
        "paid_at"                timestamptz,
        "raw_initiation"         jsonb,
        CONSTRAINT "pk_payment_intent" PRIMARY KEY ("id"),
        CONSTRAINT "uq_payment_intent_merchant_order_id" UNIQUE ("merchant_order_id")
      )
    `);
    // One ACTIVE intent per domain order; terminal-failed attempts remain as audit rows.
    await queryRunner.query(`
      CREATE UNIQUE INDEX "uq_payment_intent_active_reference"
        ON "edr_payment"."payment_intent" ("service", "reference_type", "reference_id")
        WHERE status NOT IN ('FAILED','CANCELLED') AND deleted_at IS NULL
    `);
    await queryRunner.query(`
      CREATE INDEX "idx_payment_intent_provider_txn"
        ON "edr_payment"."payment_intent" ("provider_txn_id")
    `);
    await queryRunner.query(`
      CREATE INDEX "idx_payment_intent_sweep"
        ON "edr_payment"."payment_intent" ("status", "updated_at")
    `);
    await queryRunner.query(`
      CREATE INDEX "idx_payment_intent_idempotency"
        ON "edr_payment"."payment_intent" ("service", "idempotency_key")
    `);

    await queryRunner.query(`
      CREATE TABLE "edr_payment"."payment_webhook_event" (
        "id"                uuid         NOT NULL DEFAULT gen_random_uuid(),
        "created_at"        timestamptz  NOT NULL DEFAULT now(),
        "updated_at"        timestamptz  NOT NULL DEFAULT now(),
        "deleted_at"        timestamptz,
        "provider"          varchar(16)  NOT NULL,
        "external_event_id" varchar(191) NOT NULL,
        "merchant_order_id" varchar(64),
        "provider_txn_id"   varchar(128),
        "signature_valid"   boolean      NOT NULL DEFAULT false,
        "status"            varchar(64),
        "payload"           jsonb        NOT NULL,
        "received_at"       timestamptz  NOT NULL DEFAULT now(),
        "processed_at"      timestamptz,
        "processing_error"  text,
        CONSTRAINT "pk_payment_webhook_event" PRIMARY KEY ("id")
      )
    `);
    // The webhook dedupe key: duplicate provider deliveries hit this and short-circuit.
    await queryRunner.query(`
      CREATE UNIQUE INDEX "uq_payment_webhook_event_external"
        ON "edr_payment"."payment_webhook_event" ("provider", "external_event_id")
    `);

    await queryRunner.query(`
      CREATE TABLE "edr_payment"."notification_outbox" (
        "id"             uuid        NOT NULL DEFAULT gen_random_uuid(),
        "created_at"     timestamptz NOT NULL DEFAULT now(),
        "updated_at"     timestamptz NOT NULL DEFAULT now(),
        "deleted_at"     timestamptz,
        "event_type"     varchar(32) NOT NULL,
        "service"        varchar(16) NOT NULL,
        "intent_id"      uuid        NOT NULL,
        "reference_type" varchar(16) NOT NULL,
        "reference_id"   varchar(64) NOT NULL,
        "payload"        jsonb       NOT NULL,
        "status"         varchar(16) NOT NULL DEFAULT 'PENDING',
        "attempts"       integer     NOT NULL DEFAULT 0,
        "next_retry_at"  timestamptz,
        "last_error"     text,
        "sent_at"        timestamptz,
        CONSTRAINT "pk_notification_outbox" PRIMARY KEY ("id")
      )
    `);
    await queryRunner.query(`
      CREATE INDEX "idx_notification_outbox_relay"
        ON "edr_payment"."notification_outbox" ("status", "next_retry_at")
    `);
    await queryRunner.query(`
      CREATE INDEX "idx_notification_outbox_intent"
        ON "edr_payment"."notification_outbox" ("intent_id")
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE "edr_payment"."notification_outbox"`);
    await queryRunner.query(`DROP TABLE "edr_payment"."payment_webhook_event"`);
    await queryRunner.query(`DROP TABLE "edr_payment"."payment_intent"`);
  }
}
