import { describe, expect, it } from 'vitest'
import { createPgliteClient } from '../../db/src/postgres/pglite.js'
import { isMeteringValidationError } from './errors.js'
import { pushSchema } from './migrate.js'
import { reserve } from './reserve.js'
import { meteringSchema } from './schema.js'
import type { EntitlementPolicy, PolicyStore } from './types.js'
import { usage } from './usage.js'

const NOW = new Date('2026-07-15T00:00:00.000Z')
const SUBJECT = { tenantId: 'tenant-wedge', account: 'account-wedge' }
const METER = 'api.calls'
const PERIOD = {
  id: 'period-wedge',
  startsAt: new Date('2026-07-01T00:00:00.000Z'),
  endsAt: new Date('2026-08-01T00:00:00.000Z'),
}
const UNLIMITED: EntitlementPolicy = {
  meter: METER,
  includedUnits: 0n,
  overage: 'allow',
  period: PERIOD,
  version: 'wedge-v1',
}

async function fixture() {
  const db = createPgliteClient({ schema: meteringSchema })
  await pushSchema(db)
  const policies: PolicyStore = { resolve: async () => UNLIMITED }
  return { db, deps: { db, policies, clock: () => NOW } }
}

describe('quantity magnitude bound', () => {
  it('rejects an over-bound quantity under an unlimited policy, leaving usage readable', async () => {
    const { deps } = await fixture()

    await expect(
      reserve(deps, {
        subject: SUBJECT,
        meter: METER,
        units: 10n ** 21n,
        idempotencyKey: 'wedge-request',
        expiresAt: new Date('2026-07-15T01:00:00.000Z'),
      }),
    ).rejects.toSatisfy(isMeteringValidationError)

    await expect(usage(deps, { subject: SUBJECT, meter: METER, at: NOW })).resolves.toMatchObject({
      committed: 0n,
      reserved: 0n,
    })
  })

  it('admits the largest in-bound quantity under an unlimited policy', async () => {
    const { deps } = await fixture()

    const reservation = await reserve(deps, {
      subject: SUBJECT,
      meter: METER,
      units: 10n ** 21n - 1n,
      idempotencyKey: 'inbound-request',
      expiresAt: new Date('2026-07-15T01:00:00.000Z'),
    })

    expect(reservation.reservedUnits).toBe(10n ** 21n - 1n)
    await expect(usage(deps, { subject: SUBJECT, meter: METER, at: NOW })).resolves.toMatchObject({
      reserved: 10n ** 21n - 1n,
      capacityRemaining: null,
    })
  })

  it('rejects an individually valid reserve that would overflow the reserved counter', async () => {
    const { deps } = await fixture()
    const input = {
      subject: SUBJECT,
      meter: METER,
      units: 6n * 10n ** 20n,
      expiresAt: new Date('2026-07-15T01:00:00.000Z'),
    }

    await reserve(deps, { ...input, idempotencyKey: 'cumulative-1' })
    await expect(
      reserve(deps, { ...input, idempotencyKey: 'cumulative-2' }),
    ).rejects.toSatisfy(isMeteringValidationError)
    await expect(usage(deps, { subject: SUBJECT, meter: METER, at: NOW })).resolves.toMatchObject({
      reserved: input.units,
    })
  })

  it('rejects an oversized current-policy quantity in usage', async () => {
    const db = createPgliteClient({ schema: meteringSchema })
    await pushSchema(db)
    const policies: PolicyStore = {
      resolve: async () => ({ ...UNLIMITED, includedUnits: 10n ** 21n }),
    }

    await expect(
      usage({ db, policies }, { subject: SUBJECT, meter: METER, at: NOW }),
    ).rejects.toSatisfy(isMeteringValidationError)
  })
})
