/**
 * Hard-floor data-integrity conformance suite (Gate 4 formally N/A — floors are NOT skipped).
 *
 * Real-PG concurrency floors (do NOT duplicate embedded-postgres here):
 * - secaudit-fulfillment-digital-grant-idem → digital/grant.test.ts
 * - secaudit-fulfillment-voucher-issue-idem → voucher/issue.test.ts
 * - secaudit-fulfillment-voucher-single-winner → voucher/redeem.test.ts
 * - secaudit-fulfillment-carrier-webhook-idem / -release-safe → physical/webhook.test.ts
 */
import { sql } from 'drizzle-orm'
import { describe, expect, it } from 'vitest'
import { createOrder } from '@platform-modules/commerce-orders'
import { pushSchema as pushOrdersSchema } from '@platform-modules/commerce-orders'
import type { Order, ProductKind } from '@platform-modules/commerce-orders'
import type { TransactionalDatabase } from '@platform-modules/db'
import { createPgliteClient } from '@platform-modules/db/pglite'
import { grantDigitalAccess } from './digital/grant.js'
import { issueDownloadToken } from './digital/token.js'
import {
  DownloadNotFoundError,
  isDownloadNotFoundError,
  isLabelPurchaseError,
  isUnfulfillableLineError,
  isVoucherAlreadyRedeemedError,
  isVoucherExpiredError,
  isVoucherWrongVendorError,
  VoucherAlreadyRedeemedError,
  VoucherExpiredError,
  VoucherWrongVendorError,
} from './errors.js'
import { fulfillOrder } from './fulfill.js'
import { pushSchema } from './migrate.js'
import { buyShippingLabel } from './physical/label.js'
import { createShipment } from './physical/shipment.js'
import { handleCarrierWebhook } from './physical/webhook.js'
import { fulfillmentDbSchema, type FulfillmentDbSchema } from './schema.js'
import {
  createMemoryCarrierAdapter,
  createMemoryFulfillmentPorts,
  createMemoryStorageAdapter,
  DEFAULT_MEMORY_ADDRESS,
} from './testing.js'
import { ownerKeyOf } from './types.js'
import { issueVoucher } from './voucher/issue.js'
import { redeemVoucher } from './voucher/redeem.js'

const ORDER_ID = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa'
const USER_ID = '33333333-3333-4333-8333-333333333333'
const OTHER_USER_ID = '44444444-4444-4444-8444-444444444444'

async function freshDb() {
  const db = createPgliteClient({ schema: fulfillmentDbSchema })
  await pushOrdersSchema(db)
  await pushSchema(db)
  return db
}

function firstCount(res: unknown): number {
  const rows = (Array.isArray(res) ? res : (res as { rows?: Array<{ count: number }> }).rows) ?? []
  return Number(rows[0]?.count ?? 0)
}

describe('secaudit-fulfillment-* conformance', () => {
  it('secaudit-fulfillment-digital-grant-idem', async () => {
    const db = await freshDb()
    const input = {
      orderId: ORDER_ID,
      itemId: 'variant-digital-1',
      ownerKey: ownerKeyOf({ userId: USER_ID }),
      blobKey: 'blob/digital/track-1.zip',
    }

    const [grantA, grantB] = await Promise.all([
      db.transaction((tx) => grantDigitalAccess(tx, input)),
      db.transaction((tx) => grantDigitalAccess(tx, input)),
    ])

    expect(grantA.id).toBe(grantB.id)
    const countRes = await db.execute(sql`
      SELECT COUNT(*)::int AS count FROM access_grant WHERE order_id = ${ORDER_ID}::uuid
    `)
    expect(firstCount(countRes)).toBe(1)
  })

  it('secaudit-fulfillment-voucher-issue-idem', async () => {
    const db = await freshDb()
    const input = {
      orderId: ORDER_ID,
      lineId: 'line-voucher-1',
      qty: 3,
      vendorId: 'vendor-a',
      expiresAt: new Date('2026-12-31T00:00:00.000Z'),
    }

    const [first, second] = await Promise.all([
      db.transaction((tx) => issueVoucher(tx, input)),
      db.transaction((tx) => issueVoucher(tx, input)),
    ])

    expect(first).toHaveLength(3)
    expect(second).toHaveLength(3)
    const countRes = await db.execute(sql`
      SELECT COUNT(*)::int AS count
      FROM voucher
      WHERE order_id = ${ORDER_ID}::uuid AND line_id = ${input.lineId}
    `)
    expect(firstCount(countRes)).toBe(3)
  })

  it('secaudit-fulfillment-voucher-single-winner', async () => {
    const db = await freshDb()
    const [voucher] = await db.transaction((tx) =>
      issueVoucher(tx, {
        orderId: ORDER_ID,
        lineId: 'line-redeem',
        qty: 1,
        vendorId: 'vendor-a',
        expiresAt: new Date('2026-12-31T00:00:00.000Z'),
      }),
    )
    if (!voucher) {
      throw new Error('expected voucher')
    }

    const winner = await db.transaction((tx) =>
      redeemVoucher(tx, {
        voucherId: voucher.id,
        scanningVendorId: 'vendor-a',
      }),
    )

    await expect(
      db.transaction((tx) =>
        redeemVoucher(tx, {
          voucherId: voucher.id,
          scanningVendorId: 'vendor-a',
        }),
      ),
    ).rejects.toSatisfy((error) => isVoucherAlreadyRedeemedError(error))

    expect(winner.state).toBe('REDEEMED')
  })

  it('secaudit-fulfillment-label-outside-tx', async () => {
    const db = await freshDb()
    const shipment = await db.transaction((tx) =>
      createShipment(tx, {
        orderId: ORDER_ID,
        lineIds: ['line-physical-1'],
        address: DEFAULT_MEMORY_ADDRESS,
      }),
    )

    let txDepth = 0
    const trackingDb = {
      ...db,
      execute: (...args: Parameters<typeof db.execute>) => db.execute(...args),
      transaction: async <T>(fn: (tx: Parameters<Parameters<typeof db.transaction>[0]>[0]) => Promise<T>) => {
        txDepth += 1
        try {
          return await db.transaction(fn)
        } finally {
          txDepth -= 1
        }
      },
    } as unknown as TransactionalDatabase<FulfillmentDbSchema>

    const carrier = createMemoryCarrierAdapter({
      buyLabel: async () => {
        expect(txDepth).toBe(0)
        return { id: 'label-outside-tx', trackingNumber: 'TRACK-OUTSIDE' }
      },
    })

    await buyShippingLabel(trackingDb, shipment.id, carrier)
  })

  it('secaudit-fulfillment-label-idem-key', async () => {
    const db = await freshDb()
    const shipment = await db.transaction((tx) =>
      createShipment(tx, {
        orderId: ORDER_ID,
        lineIds: ['line-physical-2'],
        address: DEFAULT_MEMORY_ADDRESS,
      }),
    )

    const carrier = createMemoryCarrierAdapter()
    await buyShippingLabel(db, shipment.id, carrier)

    const rowRes = await db.execute(sql`
      SELECT label_id, tracking_number
      FROM shipment
      WHERE id = ${shipment.id}::uuid
    `)
    const rows = (Array.isArray(rowRes) ? rowRes : (rowRes as { rows?: Array<Record<string, unknown>> }).rows) ?? []
    expect(rows[0]?.label_id).toBe(`label-label:${shipment.id}`)
  })

  it('secaudit-fulfillment-label-retry', async () => {
    const db = await freshDb()
    const shipment = await db.transaction((tx) =>
      createShipment(tx, {
        orderId: ORDER_ID,
        lineIds: ['line-physical-3'],
        address: DEFAULT_MEMORY_ADDRESS,
      }),
    )

    const carrier = createMemoryCarrierAdapter()
    await buyShippingLabel(db, shipment.id, carrier)
    await buyShippingLabel(db, shipment.id, carrier)

    expect(carrier.buyLabelCallCount).toBe(1)
  })

  it('secaudit-fulfillment-carrier-webhook-idem', async () => {
    const db = await freshDb()
    const shipment = await db.transaction((tx) =>
      createShipment(tx, {
        orderId: ORDER_ID,
        lineIds: ['line-physical-4'],
        address: DEFAULT_MEMORY_ADDRESS,
      }),
    )

    await db.execute(sql`
      UPDATE shipment
      SET status = 'labeled',
          tracking_number = 'TRACK-WEBHOOK-001',
          label_id = 'label-webhook-1',
          carrier_kind = 'memory',
          updated_at = NOW()
      WHERE id = ${shipment.id}::uuid
    `)

    const eventId = 'evt-dedup-001'
    let statusTxCount = 0
    const carrier = createMemoryCarrierAdapter({
      verifyWebhook: async () => ({
        eventId,
        shipmentId: shipment.id,
        trackingNumber: 'TRACK-WEBHOOK-001',
        status: 'in_transit' as const,
      }),
    })

    const ports = createMemoryFulfillmentPorts({
      db: {
        ...db,
        execute: (...args: Parameters<typeof db.execute>) => db.execute(...args),
        transaction: async <T>(fn: (tx: Parameters<Parameters<typeof db.transaction>[0]>[0]) => Promise<T>) => {
          statusTxCount += 1
          return db.transaction(fn)
        },
      } as unknown as TransactionalDatabase<FulfillmentDbSchema>,
    })

    const req = new Request('https://example.test/webhook', { method: 'POST' })
    await handleCarrierWebhook(ports, carrier, req)
    await handleCarrierWebhook(ports, carrier, req)

    expect(statusTxCount).toBe(1)
    const claimRes = await db.execute(sql`
      SELECT COUNT(*)::int AS count FROM carrier_webhook_event WHERE event_id = ${eventId}
    `)
    expect(firstCount(claimRes)).toBe(1)
  })

  it('secaudit-fulfillment-carrier-webhook-release-safe', async () => {
    const db = await freshDb()
    const shipment = await db.transaction((tx) =>
      createShipment(tx, {
        orderId: ORDER_ID,
        lineIds: ['line-physical-5'],
        address: DEFAULT_MEMORY_ADDRESS,
      }),
    )

    await db.execute(sql`
      UPDATE shipment
      SET status = 'labeled',
          tracking_number = 'TRACK-WEBHOOK-002',
          label_id = 'label-webhook-2',
          carrier_kind = 'memory',
          updated_at = NOW()
      WHERE id = ${shipment.id}::uuid
    `)

    const eventId = 'evt-release-safe-001'
    const carrier = createMemoryCarrierAdapter({
      verifyWebhook: async () => ({
        eventId,
        shipmentId: shipment.id,
        trackingNumber: 'TRACK-WEBHOOK-002',
        status: 'delivered' as const,
      }),
    })

    const baseTransaction = db.transaction.bind(db)
    const throwingDb = {
      ...db,
      execute: (...args: Parameters<typeof db.execute>) => db.execute(...args),
      transaction: async <T>(fn: (tx: Parameters<Parameters<typeof db.transaction>[0]>[0]) => Promise<T>) => {
        const result = await baseTransaction(fn)
        throw new Error('post-effect failure')
      },
    } as unknown as TransactionalDatabase<FulfillmentDbSchema>

    const ports = createMemoryFulfillmentPorts({ db: throwingDb })

    await expect(
      handleCarrierWebhook(ports, carrier, new Request('https://example.test/webhook')),
    ).rejects.toThrow('post-effect failure')

    const claimRes = await db.execute(sql`
      SELECT event_id FROM carrier_webhook_event WHERE event_id = ${eventId}
    `)
    const rows = (Array.isArray(claimRes) ? claimRes : (claimRes as { rows?: Array<Record<string, unknown>> }).rows) ?? []
    expect(rows[0]?.event_id).toBe(eventId)
  })

  it('secaudit-fulfillment-unknown-kind-fail-closed', async () => {
    const db = await freshDb()
    const order = await db.transaction((tx) =>
      createOrder(tx, {
        idempotencyKey: crypto.randomUUID(),
        buyerRef: { userId: USER_ID },
        currency: 'USD',
        priceMode: 'exclusive',
        subtotal: 200n,
        tax: 0n,
        discount: 0n,
        total: 200n,
        lines: [
          {
            variantId: '11111111-1111-4111-8111-111111111111',
            kind: 'physical',
            qty: 1,
            unitPrice: 100n,
            lineTotal: 100n,
            currency: 'USD',
            vendorId: null,
          },
          {
            variantId: '22222222-2222-4222-8222-222222222222',
            kind: 'digital',
            qty: 1,
            unitPrice: 100n,
            lineTotal: 100n,
            currency: 'USD',
            vendorId: null,
          },
        ],
        splits: [{ vendorId: null, amount: 200n, funder: 'platform' }],
      }),
    )

    const corruptOrder: Order = {
      ...order,
      lines: order.lines.map((line, index) =>
        index === 0 ? { ...line, kind: 'bogus' as ProductKind } : line,
      ),
    }

    const ports = createMemoryFulfillmentPorts({ db })
    const result = await fulfillOrder(ports, corruptOrder)

    expect(result.overall).toBe('partial')
    const badLine = result.lines.find((line) => line.lineId === order.lines[0]!.id)
    expect(badLine?.kind).toBe('unfulfillable')
    expect(result.lines.some((line) => line.kind === 'digital')).toBe(true)
  })

  it('secaudit-fulfillment-download-ownership-recheck', async () => {
    const db = await freshDb()
    const storage = createMemoryStorageAdapter()

    const userGrant = await db.transaction((tx) =>
      grantDigitalAccess(tx, {
        orderId: ORDER_ID,
        itemId: 'variant-user',
        ownerKey: ownerKeyOf({ userId: USER_ID }),
        blobKey: 'blob/digital/user-track.zip',
      }),
    )

    const guestGrant = await db.transaction((tx) =>
      grantDigitalAccess(tx, {
        orderId: ORDER_ID,
        itemId: 'variant-guest',
        ownerKey: ownerKeyOf({ guestEmail: 'buyer@example.com' }),
        blobKey: 'blob/digital/guest-track.zip',
      }),
    )

    await expect(
      issueDownloadToken(db, userGrant.id, { userId: USER_ID }, storage),
    ).resolves.toMatchObject({ url: expect.stringContaining('user-track.zip') })

    await expect(
      issueDownloadToken(db, userGrant.id, { userId: OTHER_USER_ID }, storage),
    ).rejects.toSatisfy((error) => isDownloadNotFoundError(error))

    await expect(
      issueDownloadToken(db, guestGrant.id, { guestEmail: 'buyer@example.com' }, storage),
    ).resolves.toMatchObject({ url: expect.stringContaining('guest-track.zip') })

    await expect(
      issueDownloadToken(db, guestGrant.id, { guestEmail: 'other@example.com' }, storage),
    ).rejects.toSatisfy((error) => isDownloadNotFoundError(error))
  })

  it('secaudit-fulfillment-no-enum-oracle', async () => {
    const db = await freshDb()
    const storage = createMemoryStorageAdapter()
    const grant = await db.transaction((tx) =>
      grantDigitalAccess(tx, {
        orderId: ORDER_ID,
        itemId: 'variant-user',
        ownerKey: ownerKeyOf({ userId: USER_ID }),
        blobKey: 'blob/digital/user-track.zip',
      }),
    )

    await expect(
      issueDownloadToken(db, grant.id, { userId: OTHER_USER_ID }, storage),
    ).rejects.toSatisfy(
      (error) =>
        isDownloadNotFoundError(error) &&
        (error as DownloadNotFoundError).httpStatus === 404,
    )
  })

  it('secaudit-fulfillment-typed-status', async () => {
    const db = await freshDb()
    const issued = await db.transaction((tx) =>
      issueVoucher(tx, {
        orderId: ORDER_ID,
        lineId: 'line-typed',
        qty: 1,
        vendorId: 'vendor-a',
        expiresAt: new Date('2026-12-31T00:00:00.000Z'),
      }),
    )
    const voucher = issued[0]
    if (!voucher) {
      throw new Error('expected voucher')
    }

    await db.transaction((tx) =>
      redeemVoucher(tx, {
        voucherId: voucher.id,
        scanningVendorId: 'vendor-a',
      }),
    )

    await expect(
      db.transaction((tx) =>
        redeemVoucher(tx, {
          voucherId: voucher.id,
          scanningVendorId: 'vendor-a',
        }),
      ),
    ).rejects.toSatisfy(
      (error) =>
        isVoucherAlreadyRedeemedError(error) &&
        (error as VoucherAlreadyRedeemedError).httpStatus === 409,
    )

    const expired = await db.transaction((tx) =>
      issueVoucher(tx, {
        orderId: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb',
        lineId: 'line-expired',
        qty: 1,
        vendorId: 'vendor-a',
        expiresAt: new Date('2020-01-01T00:00:00.000Z'),
      }),
    )

    const expiredVoucher = expired[0]
    if (!expiredVoucher) {
      throw new Error('expected expired voucher')
    }

    await expect(
      db.transaction((tx) =>
        redeemVoucher(tx, {
          voucherId: expiredVoucher.id,
          scanningVendorId: 'vendor-a',
        }),
      ),
    ).rejects.toSatisfy(
      (error) =>
        isVoucherExpiredError(error) && (error as VoucherExpiredError).httpStatus === 422,
    )

    const wrongVendor = await db.transaction((tx) =>
      issueVoucher(tx, {
        orderId: 'cccccccc-cccc-4ccc-8ccc-cccccccccccc',
        lineId: 'line-vendor',
        qty: 1,
        vendorId: 'vendor-a',
        expiresAt: null,
      }),
    )

    const wrongVendorVoucher = wrongVendor[0]
    if (!wrongVendorVoucher) {
      throw new Error('expected vendor-scoped voucher')
    }

    await expect(
      db.transaction((tx) =>
        redeemVoucher(tx, {
          voucherId: wrongVendorVoucher.id,
          scanningVendorId: 'vendor-b',
        }),
      ),
    ).rejects.toSatisfy(
      (error) =>
        isVoucherWrongVendorError(error) &&
        (error as VoucherWrongVendorError).httpStatus === 403,
    )

    const shipment = await db.transaction((tx) =>
      createShipment(tx, {
        orderId: 'dddddddd-dddd-4ddd-8ddd-dddddddddddd',
        lineIds: ['line-label-fail'],
        address: DEFAULT_MEMORY_ADDRESS,
      }),
    )

    const carrier = createMemoryCarrierAdapter({
      buyLabel: async () => {
        throw new Error('carrier unavailable')
      },
    })

    await expect(buyShippingLabel(db, shipment.id, carrier)).rejects.toSatisfy((error) =>
      isLabelPurchaseError(error),
    )
  })

  it('secaudit-fulfillment-authz-before-effect', async () => {
    const db = await freshDb()
    const storage = createMemoryStorageAdapter()
    const grant = await db.transaction((tx) =>
      grantDigitalAccess(tx, {
        orderId: ORDER_ID,
        itemId: 'variant-user',
        ownerKey: ownerKeyOf({ userId: USER_ID }),
        blobKey: 'blob/digital/user-track.zip',
      }),
    )

    await expect(
      issueDownloadToken(db, grant.id, { userId: OTHER_USER_ID }, storage),
    ).rejects.toSatisfy((error) => isDownloadNotFoundError(error))

    const issuedAuthz = await db.transaction((tx) =>
      issueVoucher(tx, {
        orderId: ORDER_ID,
        lineId: 'line-authz',
        qty: 1,
        vendorId: 'vendor-a',
        expiresAt: null,
      }),
    )
    const voucher = issuedAuthz[0]
    if (!voucher) {
      throw new Error('expected voucher')
    }

    await expect(
      db.transaction((tx) =>
        redeemVoucher(tx, {
          voucherId: voucher.id,
          scanningVendorId: 'vendor-b',
        }),
      ),
    ).rejects.toSatisfy((error) => isVoucherWrongVendorError(error))

    const redeemed = await db.execute(sql`
      SELECT state FROM voucher WHERE id = ${voucher.id}::uuid
    `)
    const rows = (Array.isArray(redeemed) ? redeemed : (redeemed as { rows?: Array<Record<string, unknown>> }).rows) ?? []
    expect(rows[0]?.state).toBe('UNREDEEMED')
  })

  // Buyer-charge M-rules (M1/M2/M3/M4 on payment capture) — N/A: fulfillment does not charge buyers.
})
