/**
 * P2-1 — monitor claim uses SELECT ... FOR UPDATE SKIP LOCKED inside a
 * ReadCommitted transaction (mirroring NotificationOutbox.claimDue).
 *
 * Two workers running simultaneously must NOT pull the same row twice.
 * We can't prove that with a unit test without a real DB, so the contract
 * test asserts the SQL shape that gives us the guarantee.
 */

jest.mock('@/lib/prisma', () => ({
    prisma: {
        monitor: {
            updateMany: jest.fn().mockResolvedValue({ count: 0 }),
        },
        $transaction: jest.fn(),
    },
}));

jest.mock('@/lib/notification-system', () => ({
    NotificationDispatcher: { emit: jest.fn() },
}));

jest.mock('@/lib/event-bus', () => ({ EventBus: { emit: jest.fn() } }));

import { prisma } from '@/lib/prisma';
import { runPendingChecks } from '../monitor-engine';

describe('P2-1 monitor claim uses FOR UPDATE SKIP LOCKED', () => {
    it('emits the locking SELECT inside a ReadCommitted transaction', async () => {
        const queryRawUnsafe = jest.fn().mockResolvedValue([]);
        const updateMany = jest.fn();
        const findMany = jest.fn().mockResolvedValue([]);
        let isolationCaptured: unknown = null;
        (prisma.$transaction as jest.Mock).mockImplementationOnce(async (fn, opts) => {
            isolationCaptured = opts?.isolationLevel;
            return fn({
                $queryRawUnsafe: queryRawUnsafe,
                monitor: { updateMany, findMany },
            });
        });

        await runPendingChecks(50);

        const sql = String(queryRawUnsafe.mock.calls[0][0]);
        expect(sql).toMatch(/SELECT id FROM Monitor/i);
        expect(sql).toMatch(/FOR UPDATE SKIP LOCKED/i);
        expect(sql).toMatch(/LIMIT \?/i);
        expect(isolationCaptured).toBe('ReadCommitted');
    });

    it('does not touch downstream tables when no rows are claimed', async () => {
        const queryRawUnsafe = jest.fn().mockResolvedValue([]);
        const updateMany = jest.fn();
        const findMany = jest.fn().mockResolvedValue([]);
        (prisma.$transaction as jest.Mock).mockImplementationOnce(async (fn) =>
            fn({
                $queryRawUnsafe: queryRawUnsafe,
                monitor: { updateMany, findMany },
            })
        );

        const result = await runPendingChecks(50);
        expect(result).toEqual([]);
        expect(updateMany).not.toHaveBeenCalled();
        expect(findMany).not.toHaveBeenCalled();
    });
});
