import { PGlite } from '@electric-sql/pglite'
import { drizzle } from 'drizzle-orm/pglite'
import { describe, expect, it } from 'vitest'
import type { TransactionalDatabase } from '@platform-modules/db'
import { withTransactionIdentity } from '@platform-modules/db'
import {
  createMetering,
  meteringSchema,
  pushSchema,
} from '../../../packages/metering/src/index.js'
import type {
  EntitlementPolicy,
  MeteringSchema,
  PolicyStore,
  SubjectRef,
} from '../../../packages/metering/src/index.js'

const SUBJECT: SubjectRef = { tenantId: 'consumer-tenant', account: 'consumer-account' }
const METER = 'ocr.pages'
const NOW = new Date('2026-07-15T00:00:00.000Z')
const POLICY: EntitlementPolicy = {
  meter: METER,
  includedUnits: 10n,
  overage: 'deny',
  period: {
    id: 'consumer-period',
    startsAt: new Date('2026-07-01T00:00:00.000Z'),
    endsAt: new Date('2026-08-01T00:00:00.000Z'),
  },
  version: 'consumer-policy-v1',
}

describe('metering consumer fixture (Gate 3)', () => {
  it('drives resolve -> reserve -> commit -> usage through the public barrel', async () => {
    const client = new PGlite()
    const db = withTransactionIdentity(
      drizzle(client, { schema: meteringSchema }),
    ) as unknown as TransactionalDatabase<MeteringSchema>
    await pushSchema(db)

    const resolvedAt: Date[] = []
    const policies: PolicyStore = {
      resolve: async (_subject, _meter, at) => {
        resolvedAt.push(at)
        return POLICY
      },
    }
    const metering = createMetering({ db, policies, clock: () => NOW })

    const reservation = await metering.reserve({
      subject: SUBJECT,
      meter: METER,
      units: 4n,
      idempotencyKey: 'consumer-reservation-1', // gitleaks:allow
      expiresAt: new Date('2026-07-15T01:00:00.000Z'),
    })
    expect(reservation.period).toEqual(POLICY.period)
    expect(reservation.appliedPolicy).toEqual({
      includedUnits: 10n,
      overage: 'deny',
      version: POLICY.version,
    })

    const committed = await metering.commit(reservation.id, 3n)
    expect(committed.committedUnits).toBe(3n)
    expect(committed.releasedUnits).toBe(1n)

    await expect(
      metering.usage({ subject: SUBJECT, meter: METER, at: NOW }),
    ).resolves.toEqual({
      period: POLICY.period,
      committed: 3n,
      reserved: 0n,
      includedRemaining: 7n,
      capacityRemaining: 7n,
    })
    expect(resolvedAt).toEqual([NOW, NOW])

    await client.close()
  })
})
