/**
 * P0-5 — MonitorService read paths scope by userId for non-admins.
 *
 * The diligence audit flagged that getMonitors and getMonitorsForDashboard
 * filtered only by region (country) for non-admins, letting two users in
 * the same country see each other's monitors. These tests pin the new
 * contract: non-admin → WHERE userId = ctx.userId; admin → no userId
 * filter.
 */

jest.mock('@/lib/prisma', () => {
    const monitor = { findMany: jest.fn(), count: jest.fn(), update: jest.fn() };
    const country = { findFirst: jest.fn().mockResolvedValue(null), findMany: jest.fn().mockResolvedValue([]) };
    const user = { findUnique: jest.fn() };
    const statusIncident = { findMany: jest.fn().mockResolvedValue([]) };
    const heartbeat = { findFirst: jest.fn().mockResolvedValue(null) };
    return {
        prisma: {
            monitor,
            country,
            user,
            statusIncident,
            heartbeat,
            $transaction: jest.fn().mockImplementation((ops: unknown[]) => {
                // For getMonitors: [count, findMany] → return [0, []]
                return Promise.all(ops as Promise<unknown>[]);
            }),
        },
    };
});

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

jest.mock('@/lib/services/audit.service', () => ({
    AuditService: { log: jest.fn() },
}));

jest.mock('@/lib/services/geolocation.service', () => ({
    GeoLocationService: { getMonitorLocation: jest.fn().mockResolvedValue(null) },
}));

jest.mock('@/lib/authorization/monitor.authz', () => ({
    MonitorAuthorization: {
        assertCanWrite: jest.fn(),
        assertCanWriteMany: jest.fn(),
        filterWritable: jest.fn().mockResolvedValue([]),
    },
}));

import { prisma } from '@/lib/prisma';
import { MonitorService } from '../monitor.service';

const monitorFindMany = prisma.monitor.findMany as jest.Mock;
const monitorCount = prisma.monitor.count as jest.Mock;

beforeEach(() => {
    jest.clearAllMocks();
    monitorCount.mockResolvedValue(0);
    monitorFindMany.mockResolvedValue([]);
});

describe('MonitorService.getMonitors — tenant scoping', () => {
    it('non-admin where clause includes userId', async () => {
        await MonitorService.getMonitors(42, false);
        // $transaction is called with [count, findMany]; both received the
        // same where clause.
        const txnCalls = (prisma.$transaction as jest.Mock).mock.calls[0][0] as unknown[];
        expect(txnCalls.length).toBe(2);
        // Read the where from the count call (which is built by passing
        // { where: whereClause } to prisma.monitor.count).
        const countWhere = monitorCount.mock.calls[0][0].where;
        expect(countWhere.userId).toBe(42);
        expect(countWhere.deletedAt).toBeNull();
    });

    it('admin where clause omits userId', async () => {
        await MonitorService.getMonitors(1, true);
        const countWhere = monitorCount.mock.calls[0][0].where;
        expect(countWhere.userId).toBeUndefined();
    });

    it('non-admin where clause still respects explicit region filter', async () => {
        await MonitorService.getMonitors(42, false, { region: 'KE' });
        const countWhere = monitorCount.mock.calls[0][0].where;
        expect(countWhere.userId).toBe(42);
        expect(countWhere.region).toBe('KE');
    });
});

describe('MonitorService.getMonitorsForDashboard — tenant scoping', () => {
    it('non-admin dashboard where clause includes userId', async () => {
        await MonitorService.getMonitorsForDashboard(42, false, {
            page: 1,
            limit: 10,
        });
        const where = monitorFindMany.mock.calls[0][0].where;
        expect(where.userId).toBe(42);
    });

    it('admin dashboard where clause omits userId', async () => {
        await MonitorService.getMonitorsForDashboard(1, true, {
            page: 1,
            limit: 10,
        });
        const where = monitorFindMany.mock.calls[0][0].where;
        expect(where.userId).toBeUndefined();
    });
});
