import { RbacService } from './rbac.service';

describe('RbacService seedData', () => {
  it('migrates the legacy teacher role and replaces broad permissions with the teaching matrix', async () => {
    const permissions = [
      { id: 1, code: 'profile:view', name: '查看个人资料', group: 'profile' },
      { id: 2, code: 'notification:view', name: '查看通知', group: 'notification' },
      { id: 3, code: 'student:view', name: '查看学生', group: 'student' },
      { id: 4, code: 'class:view', name: '查看班级', group: 'class' },
      { id: 5, code: 'schedule:view', name: '查看排课', group: 'schedule' },
      { id: 6, code: 'attendance:view', name: '查看考勤', group: 'attendance' },
      { id: 7, code: 'attendance:create', name: '新增考勤', group: 'attendance' },
      { id: 8, code: 'teacher-workspace:view', name: '教师工作台', group: 'teacher-workspace' },
      { id: 9, code: 'room:view', name: '查看宿舍', group: 'room' },
      { id: 10, code: 'schedule:create', name: '新增排课', group: 'schedule' },
    ];
    const teacherRole = {
      id: 1,
      name: '老师',
      code: 'teacher',
      description: '旧角色',
      isSystem: true,
      status: 1,
      permissions: [permissions[2], permissions[3], permissions[8]],
    };

    const permRepo = {
      findOne: jest.fn(
        async ({ where }: any) => permissions.find((permission) => permission.code === where.code) ?? null,
      ),
      create: jest.fn((value) => value),
      save: jest.fn(async (value) => value),
      find: jest.fn(async (options?: any) => {
        if (options?.where?.code) {
          return permissions.filter((permission) => permission.code === 'profile:view');
        }
        return permissions;
      }),
      remove: jest.fn(async (value) => value),
    };
    const roleRepo = {
      findOne: jest.fn(async ({ where }: any) =>
        where.code === 'teacher' || where.name === '老师' ? teacherRole : null,
      ),
      create: jest.fn((value) => ({ ...value, permissions: [] })),
      save: jest.fn(async (value) => value),
      find: jest.fn(async () => [teacherRole]),
    };
    const userRepo = { count: jest.fn(async () => 1), create: jest.fn(), save: jest.fn() };

    const service = new RbacService(
      permRepo as never,
      roleRepo as never,
      userRepo as never,
      {} as never,
      {} as never,
      {} as never,
      {} as never,
      {} as never,
    );

    await service.seedData();

    expect(teacherRole.name).toBe('任课老师');
    expect(teacherRole.permissions.map((permission) => permission.code)).toEqual(
      expect.arrayContaining([
        'notification:view',
        'teacher-workspace:view',
        'schedule:view',
        'attendance:create',
      ]),
    );
    expect(teacherRole.permissions.map((permission) => permission.code)).not.toContain(
      'schedule:create',
    );
    expect(teacherRole.permissions.map((permission) => permission.code)).not.toContain('profile:view');
    expect(teacherRole.permissions.map((permission) => permission.code)).not.toContain('student:view');
    expect(teacherRole.permissions.map((permission) => permission.code)).not.toContain('class:view');
    expect(teacherRole.permissions.map((permission) => permission.code)).not.toContain('room:view');
  });
});

describe('RbacService legacy role consolidation', () => {
  it('moves users from duplicate accommodation roles before deleting the duplicates', async () => {
    const permissions = [
      { id: 1, code: 'profile:view', name: '查看个人资料', group: 'profile' },
      { id: 2, code: 'room:view', name: '查看宿舍', group: 'room' },
      { id: 3, code: 'expense:view', name: '查看费用', group: 'expense' },
      { id: 4, code: 'student:basic-view', name: '学生基础信息', group: 'student-scope' },
    ];
    const targetRole: any = {
      id: 10,
      name: '住宿运营管理员',
      code: 'accommodation_operations',
      description: '',
      isSystem: true,
      status: 1,
      permissions: [],
      users: [],
    };
    const legacyRole: any = {
      id: 11,
      name: '财务',
      code: 'finance',
      description: '',
      isSystem: true,
      status: 1,
      permissions: [],
      users: [{ id: 21 }],
    };
    const user: any = { id: 21, roles: [legacyRole] };
    const permRepo = {
      findOne: jest.fn(async ({ where }: any) => permissions.find((item) => item.code === where.code) ?? null),
      create: jest.fn((value) => value),
      save: jest.fn(async (value) => value),
      find: jest.fn(async (options?: any) => {
        if (options?.where?.code) {
          return permissions.filter((permission) => permission.code === 'profile:view');
        }
        return permissions;
      }),
      remove: jest.fn(async (value) => value),
    };
    const roleRepo = {
      findOne: jest.fn(async () => targetRole),
      create: jest.fn((value) => ({ ...value, permissions: [] })),
      save: jest.fn(async (value) => value),
      find: jest.fn(async () => [targetRole, legacyRole]),
      remove: jest.fn(async (value) => value),
    };
    const userRepo = {
      count: jest.fn(async () => 1),
      findOne: jest.fn(async () => user),
      save: jest.fn(async (value) => value),
    };
    const service = new RbacService(
      permRepo as never,
      roleRepo as never,
      userRepo as never,
      {} as never,
      {} as never,
      {} as never,
      {} as never,
      {} as never,
    );

    await service.seedData();

    expect(user.roles).toEqual([targetRole]);
    expect(userRepo.save).toHaveBeenCalledWith(user);
    expect(roleRepo.remove).toHaveBeenCalledWith(legacyRole);
  });
});
