export * from './types.js'
export * from './errors.js'
export * from './schema.js'
export { meteringSchema as schema } from './schema.js'
export * from './migrate.js'
export * from './resolve.js'
export * from './reserve.js'
export * from './commit.js'
export * from './release.js'
export * from './sweep.js'
export * from './usage.js'
export * from './rate.js'

import type { Schema } from '@platform-modules/db'
import { commit as commitOperation } from './commit.js'
import { expireStale as expireStaleOperation } from './sweep.js'
import { release as releaseOperation } from './release.js'
import { reserve as reserveOperation } from './reserve.js'
import { resolve as resolveOperation } from './resolve.js'
import { usage as usageOperation } from './usage.js'
import type {
  Clock,
  MeteringDatabase,
  MeteringLedgerPort,
  MeteringService,
  PolicyStore,
  RatingStore,
} from './types.js'

export function createMetering<S extends Schema = Record<string, never>>(input: {
  db: MeteringDatabase<S>
  policies: PolicyStore
  clock?: Clock
  rating?: RatingStore
  ledger?: MeteringLedgerPort
}): MeteringService {
  const clock = input.clock ?? (() => new Date())

  return {
    resolve: (subject, meter, at) => resolveOperation({ policies: input.policies }, subject, meter, at),
    reserve: (reserveInput) =>
      reserveOperation(
        { db: input.db, policies: input.policies, clock },
        reserveInput,
      ),
    commit: (reservationId, actualUnits) =>
      commitOperation(
        { db: input.db, clock, rating: input.rating },
        reservationId,
        actualUnits,
      ),
    release: (reservationId) => releaseOperation({ db: input.db }, reservationId),
    expireStale: (before, limit) => expireStaleOperation({ db: input.db }, before, limit),
    usage: (query) => usageOperation({ db: input.db, policies: input.policies }, query),
  }
}
