// @vitest-environment node
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'
import { sql } from 'drizzle-orm'
import { makeTestDb, closeTestDb, resetTables, type TestDb } from './pglite-db.js'
import { createUser, createReferralLink, createReferral } from './fixtures.js'

describe('PGLite fraud oracle harness', () => {
  let testDb: TestDb

  beforeAll(async () => {
    testDb = await makeTestDb()
  })
  afterAll(async () => {
    await closeTestDb()
  })
  beforeEach(async () => {
    await resetTables(testDb)
  })

  it('boots PGLite with affiliate-owned ledger + side-table contract', async () => {
    const { id: ownerId } = await createUser(testDb)
    const { id: linkId } = await createReferralLink(testDb, ownerId)
    const { id: refereeId } = await createUser(testDb, { email: 'referee@example.com' })
    const { id: referralId } = await createReferral(testDb, {
      referrerUserId: ownerId,
      refereeUserId: refereeId,
      linkId,
    })

    const entryId = crypto.randomUUID()
    await testDb.execute(sql`
      INSERT INTO ledger_entries (id, delta, reason, idempotency_key)
      VALUES (${entryId}, 1000, 'earn', ${`idem-${entryId}`})
    `)

    const affiliateEntry = (await testDb.execute(sql`
      INSERT INTO affiliate_entries (entry_id, owner_id, entry_type, source_type, source_id, referral_id)
      VALUES (${entryId}, ${ownerId}, 'affiliate_commission', 'purchase', 'p1', ${referralId})
      RETURNING entry_id
    `)) as { rows: Array<{ entry_id: string }> }
    expect(affiliateEntry.rows).toHaveLength(1)

    const vesting = (await testDb.execute(sql`
      INSERT INTO wallet_vesting (owner_id, pending_minor)
      VALUES (${ownerId}, 1000)
      RETURNING owner_id
    `)) as { rows: Array<{ owner_id: string }> }
    expect(vesting.rows[0]).toMatchObject({ owner_id: ownerId })
  })

  it('resetTables isolates rows between cases', async () => {
    await createUser(testDb)
    await resetTables(testDb)
    const users = (await testDb.execute(sql`SELECT COUNT(*)::int AS cnt FROM users`)) as {
      rows: Array<{ cnt: number }>
    }
    expect(users.rows[0]?.cnt).toBe(0)
  })
})
