jest.mock('../../src/database', () => {
  const tx = { __tx: true };
  const prisma = {
    $transaction: jest.fn(async (fn: (tx: unknown) => Promise<unknown>) => fn(tx)),
  };
  return { prisma };
});

import { prisma } from '../../src/database';
import { transaction, withTransaction } from '../../src/core/db';

describe('core/db transaction helpers', () => {
  beforeEach(() => {
    (prisma.$transaction as jest.Mock).mockClear();
  });

  test('transaction() executes callback via prisma.$transaction', async () => {
    const result = await transaction(async (_tx) => {
      return 123;
    });

    expect(result).toBe(123);
    expect(prisma.$transaction).toHaveBeenCalledTimes(1);
  });

  test('transaction() propagates error (rollback is handled by Prisma)', async () => {
    await expect(
      transaction(async () => {
        throw new Error('boom');
      }),
    ).rejects.toThrow('boom');

    expect(prisma.$transaction).toHaveBeenCalledTimes(1);
  });

  test('withTransaction() starts a new transaction for root client', async () => {
    const rootClient = prisma as unknown as { $transaction: (fn: any) => Promise<any> };

    const result = await withTransaction(rootClient as any, async (_tx) => 'ok');

    expect(result).toBe('ok');
    expect(prisma.$transaction).toHaveBeenCalledTimes(1);
  });

  test('withTransaction() reuses existing tx client (does not nest)', async () => {
    const txClient = {} as any; // does not have $transaction

    const result = await withTransaction(txClient, async (_tx) => 'ok');

    expect(result).toBe('ok');
    expect(prisma.$transaction).toHaveBeenCalledTimes(0);
  });
});

