import { eq, sql } from 'drizzle-orm'
import { describe, expect, it } from 'vitest'
import { createPgliteClient } from '@platform-modules/db/pglite'

import { pressZoneInitSql, pressZoneSchema, walletBalances } from '../schema.js'
import { debitCredits, periodKey, seedPeriodWallet } from './wallet.js'

async function createTestDb() {
  const db = createPgliteClient({ schema: pressZoneSchema })

  for (const statement of pressZoneInitSql.split(';').map((part) => part.trim()).filter(Boolean)) {
    await db.execute(sql.raw(statement))
  }

  return db
}

async function readBalance(
  db: ReturnType<typeof createPgliteClient<typeof pressZoneSchema>>,
  ownerId: string,
): Promise<bigint> {
  const [row] = await db
    .select({ balance: walletBalances.balance })
    .from(walletBalances)
    .where(eq(walletBalances.ownerId, ownerId))
    .limit(1)

  return row?.balance ?? 0n
}

describe('periodKey', () => {
  it('formats the period wallet owner id as <account>:<plugin>:<period>', () => {
    expect(periodKey('acct_123', 'translate', '2026-07')).toBe('acct_123:translate:2026-07')
  })
})

describe('seedPeriodWallet + debitCredits', () => {
  it('upserts the period wallet and debits within the seeded balance', async () => {
    const db = await createTestDb()
    const key = periodKey('acct_123', 'translate', '2026-07')

    await seedPeriodWallet(db, key, 3n)
    await seedPeriodWallet(db, key, 10n)

    expect(await readBalance(db, key)).toBe(10n)
    await expect(debitCredits(db, key, 4n)).resolves.toEqual({ ok: true })
    expect(await readBalance(db, key)).toBe(6n)
  })

  it('returns ok:false and leaves the balance unchanged when the debit exceeds the balance', async () => {
    const db = await createTestDb()
    const key = periodKey('acct_456', 'translate', '2026-07')

    await seedPeriodWallet(db, key, 2n)

    await expect(debitCredits(db, key, 3n)).resolves.toEqual({ ok: false })
    expect(await readBalance(db, key)).toBe(2n)
  })

  it('allows exactly one concurrent debit against a one-credit balance', async () => {
    const db = await createTestDb()
    const key = periodKey('acct_789', 'translate', '2026-07')

    await seedPeriodWallet(db, key, 1n)

    const results = await Promise.all([debitCredits(db, key, 1n), debitCredits(db, key, 1n)])

    expect(results.filter((result) => result.ok).length).toBe(1)
    expect(await readBalance(db, key)).toBe(0n)
  })
})
