import { mkdtempSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { EntraGroupMapError } from 'shared-auth';
import { loadEntraGroupToRoleResolver } from './load-entra-group-map';

function tmpFile(name: string, contents: string): string {
  const dir = mkdtempSync(join(tmpdir(), 'entra-map-'));
  const path = join(dir, name);
  writeFileSync(path, contents, 'utf8');
  return path;
}

function noopWarn(): { onWarn: jest.Mock } {
  return { onWarn: jest.fn() };
}

describe('loadEntraGroupToRoleResolver', () => {
  it('returns an empty resolver and warns when ENTRA_GROUP_MAP_PATH is unset', () => {
    const { onWarn } = noopWarn();
    const { resolver, sourcePath } = loadEntraGroupToRoleResolver({
      env: {},
      onWarn,
    });
    expect(resolver.size).toBe(0);
    expect(sourcePath).toBeNull();
    expect(onWarn).toHaveBeenCalledWith('auth.entra_group_map_path_unset', expect.any(Object));
  });

  it('returns an empty resolver and warns when the file cannot be read', () => {
    const { onWarn } = noopWarn();
    const { resolver, sourcePath } = loadEntraGroupToRoleResolver({
      env: { ENTRA_GROUP_MAP_PATH: '/tmp/definitely-not-a-real-path-xyz.json' },
      onWarn,
    });
    expect(resolver.size).toBe(0);
    expect(sourcePath).toBe('/tmp/definitely-not-a-real-path-xyz.json');
    expect(onWarn).toHaveBeenCalledWith(
      'auth.entra_group_map_file_unreadable',
      expect.objectContaining({ path: '/tmp/definitely-not-a-real-path-xyz.json' }),
    );
  });

  it('throws on malformed JSON', () => {
    const path = tmpFile('bad.json', '{ not json');
    expect(() =>
      loadEntraGroupToRoleResolver({
        env: { ENTRA_GROUP_MAP_PATH: path },
        onWarn: jest.fn(),
      }),
    ).toThrow(EntraGroupMapError);
  });

  it('throws when the JSON is not an object', () => {
    const path = tmpFile('arr.json', '["collaborateur"]');
    expect(() =>
      loadEntraGroupToRoleResolver({
        env: { ENTRA_GROUP_MAP_PATH: path },
        onWarn: jest.fn(),
      }),
    ).toThrow(EntraGroupMapError);
  });

  it('throws when a value is not a string', () => {
    const path = tmpFile(
      'bad-val.json',
      JSON.stringify({ '11111111-1111-1111-1111-111111111111': 42 }),
    );
    expect(() =>
      loadEntraGroupToRoleResolver({
        env: { ENTRA_GROUP_MAP_PATH: path },
        onWarn: jest.fn(),
      }),
    ).toThrow(EntraGroupMapError);
  });

  it('returns a populated resolver on a valid map', () => {
    const path = tmpFile(
      'good.json',
      JSON.stringify({
        '11111111-1111-1111-1111-111111111111': 'collaborateur',
        '22222222-2222-2222-2222-222222222222': 'rh',
      }),
    );
    const { resolver, sourcePath } = loadEntraGroupToRoleResolver({
      env: { ENTRA_GROUP_MAP_PATH: path },
      onWarn: jest.fn(),
    });
    expect(resolver.size).toBe(2);
    expect(sourcePath).toBe(path);
    expect(resolver.coveredRoles()).toEqual(['collaborateur', 'rh']);
  });
});
