import type { PrismaService } from '../prisma/prisma.service';
import { PermissionsService } from './permissions.service';

const row = (overrides: Partial<Record<string, unknown>> = {}) => ({
  id: 'p1',
  roleId: 'role-1',
  objectCategory: 'WORK_ORDERS',
  canView: true,
  canViewOther: false,
  canCreate: false,
  canEdit: true,
  canDelete: false,
  ...overrides,
});

describe('PermissionsService (matrice en base, cache 60 s)', () => {
  let findMany: jest.Mock;
  let service: PermissionsService;

  beforeEach(() => {
    jest.useFakeTimers();
    findMany = jest.fn().mockResolvedValue([row()]);
    service = new PermissionsService({
      permission: { findMany },
    } as unknown as PrismaService);
  });

  afterEach(() => jest.useRealTimers());

  it('applique les cinq droits de la ligne', async () => {
    await expect(service.can('role-1', 'WORK_ORDERS', 'view')).resolves.toBe(true);
    await expect(service.can('role-1', 'WORK_ORDERS', 'edit')).resolves.toBe(true);
    await expect(service.can('role-1', 'WORK_ORDERS', 'viewOther')).resolves.toBe(false);
    await expect(service.can('role-1', 'WORK_ORDERS', 'create')).resolves.toBe(false);
    await expect(service.can('role-1', 'WORK_ORDERS', 'delete')).resolves.toBe(false);
  });

  it('refuse une catégorie sans ligne (fermé par défaut)', async () => {
    await expect(service.can('role-1', 'SETTINGS', 'view')).resolves.toBe(false);
  });

  it('ne relit la base qu’à l’expiration du cache (60 s)', async () => {
    await service.can('role-1', 'WORK_ORDERS', 'view');
    await service.can('role-1', 'WORK_ORDERS', 'edit');
    expect(findMany).toHaveBeenCalledTimes(1);

    jest.advanceTimersByTime(59_000);
    await service.can('role-1', 'WORK_ORDERS', 'view');
    expect(findMany).toHaveBeenCalledTimes(1);

    jest.advanceTimersByTime(2_000);
    await service.can('role-1', 'WORK_ORDERS', 'view');
    expect(findMany).toHaveBeenCalledTimes(2);
  });

  it('invalidate() force la relecture immédiate', async () => {
    await service.can('role-1', 'WORK_ORDERS', 'view');
    service.invalidate('role-1');
    await service.can('role-1', 'WORK_ORDERS', 'view');
    expect(findMany).toHaveBeenCalledTimes(2);
  });
});
