import { sql } from 'drizzle-orm'
import { describe, expect, it } from 'vitest'
import type { Querier } from '@platform-modules/db'
import { createPgliteClient } from '../../db/src/postgres/pglite.js'
import { PromoMigrateError, isPromoMigrateError, pushSchema } from './migrate.js'
import { promotionsSchema } from './schema.js'

describe('commerce-promotions migrate', () => {
  it('pushSchema is idempotent on a fresh and re-run DB', async () => {
    const db = createPgliteClient({ schema: promotionsSchema })
    await pushSchema(db)
    await expect(pushSchema(db)).resolves.toBeUndefined()
  })

  it('adds max discount and max order columns to an existing promo table', async () => {
    const db = createPgliteClient({ schema: promotionsSchema })
    await db.execute(sql`
      CREATE TABLE promo (
        id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
        code text NOT NULL,
        kind text NOT NULL,
        value_bps integer,
        value_amount bigint,
        currency text,
        bogo_buy_qty integer,
        bogo_get_qty integer,
        scope jsonb NOT NULL,
        eligibility jsonb NOT NULL,
        funder text NOT NULL,
        max_uses integer,
        per_user_cap integer,
        uses integer NOT NULL DEFAULT 0,
        starts_at timestamptz,
        ends_at timestamptz,
        min_order_amount bigint,
        active boolean NOT NULL DEFAULT true,
        vendor_id text,
        created_at timestamptz NOT NULL DEFAULT NOW(),
        updated_at timestamptz NOT NULL DEFAULT NOW()
      )
    `)

    await pushSchema(db)
    await pushSchema(db)

    const columns = await db.execute(sql`
      SELECT column_name
      FROM information_schema.columns
      WHERE table_name = 'promo'
        AND column_name IN ('max_discount_amount', 'max_order_amount')
      ORDER BY column_name
    `)

    expect(columns.rows).toEqual([
      { column_name: 'max_discount_amount' },
      { column_name: 'max_order_amount' },
    ])

    await expect(
      db.execute(sql`
        INSERT INTO promo (
          code,
          kind,
          max_discount_amount,
          scope,
          eligibility,
          funder
        )
        VALUES (
          'BAD-DISCOUNT-CAP',
          'percentage',
          0,
          '{"kind":"all"}'::jsonb,
          '{}'::jsonb,
          'platform'
        )
      `),
    ).rejects.toThrow()

    await expect(
      db.execute(sql`
        INSERT INTO promo (
          code,
          kind,
          max_order_amount,
          scope,
          eligibility,
          funder
        )
        VALUES (
          'BAD-ORDER-CAP',
          'percentage',
          0,
          '{"kind":"all"}'::jsonb,
          '{}'::jsonb,
          'platform'
        )
      `),
    ).rejects.toThrow()
  })

  it('wraps execute failures in PromoMigrateError', async () => {
    const failing = {
      execute: async () => {
        throw new Error('boom: bad ddl')
      },
    } as unknown as Querier<typeof promotionsSchema>

    await expect(pushSchema(failing)).rejects.toMatchObject({
      name: 'PromoMigrateError',
      code: 'PROMO_MIGRATE',
    })
    await expect(pushSchema(failing)).rejects.toThrow(/boom: bad ddl/)
  })

  it('isPromoMigrateError narrows structurally', () => {
    expect(isPromoMigrateError(new PromoMigrateError('boom'))).toBe(true)
    expect(isPromoMigrateError({ name: 'PromoMigrateError', code: 'PROMO_MIGRATE' })).toBe(true)
    expect(isPromoMigrateError({})).toBe(false)
    expect(isPromoMigrateError(null)).toBe(false)
    expect(isPromoMigrateError(new Error('promo migrate: boom'))).toBe(false)
  })
})
