jest.mock('../../../../src/api/modules/users/infrastructure/dataAccessObjects/userDAO');
import { faker } from '@faker-js/faker/locale/en_US';
import { ListOptions, UserStatus } from '@humand-packages/common';
import { MockProxy, mock } from 'jest-mock-extended';
import { UserDAO } from '../../../../src/api/modules/users/infrastructure/dataAccessObjects/userDAO';
import { OrganizationChartsService } from '../../../../src/api/modules/organizationCharts/business/services/organizationChartsService';
import { PerformanceReviewUsersAdapter } from '../../../../src/api/modules/performanceReviews/infrastructure/adapters/performanceReviewUsersAdapter';
import { UserListAllFilters } from '../../../../src/api/modules/users/business/types/listAllFilters';
import { UsersService } from '../../../../src/api/modules/users/business/services/usersService';
import { fakePositiveInteger } from '../../../common/common';

let usersService: MockProxy<UsersService>;
let organizationChartsService: MockProxy<OrganizationChartsService>;
let usersAdapter: PerformanceReviewUsersAdapter;

describe('PerformanceReviewUsersAdapter', () => {
    beforeEach(() => {
        usersService = mock<UsersService>();
        organizationChartsService = mock<OrganizationChartsService>();
        usersAdapter = new PerformanceReviewUsersAdapter(usersService, organizationChartsService);
    });

    describe('getUsersByPks', () => {
        let userIds: number[];

        beforeEach(() => {
            userIds = [fakePositiveInteger()];
        });

        it('should return empty if no users exist', async () => {
            usersService.findByPks.mockResolvedValueOnce([]);

            const result = await usersAdapter.getUsersByPks(userIds);

            expect(result).toHaveLength(0);
        });

        it('should list users if one exist', async () => {
            const user = new UserDAO();
            user.id = fakePositiveInteger();

            user.firstName = faker.person.firstName();
            user.lastName = faker.person.lastName();
            user.employeeInternalId = faker.word.noun();

            usersService.findByPks.mockResolvedValueOnce([user]);

            const result = await usersAdapter.getUsersByPks(userIds);

            expect(result).toHaveLength(1);
            expect(result[0].firstName).toBe(user.firstName);
            expect(result[0].lastName).toBe(user.lastName);
            expect(result[0].id).toBe(user.id);
            expect(result[0].employeeInternalId).toBe(user.employeeInternalId);
        });
    });

    describe('getUser', () => {
        let userId: number;
        let instanceId: number;

        beforeEach(() => {
            userId = fakePositiveInteger();
            instanceId = fakePositiveInteger();
        });

        it('should return user if one exist', async () => {
            const user = new UserDAO();
            user.id = fakePositiveInteger();

            user.firstName = faker.person.firstName();
            user.lastName = faker.person.lastName();
            user.employeeInternalId = faker.word.noun();

            usersService.findByPk.mockResolvedValueOnce(user);

            const result = await usersAdapter.getUser(instanceId, userId);

            expect(result.firstName).toBe(user.firstName);
            expect(result.lastName).toBe(user.lastName);
            expect(result.id).toBe(user.id);
            expect(result.employeeInternalId).toBe(user.employeeInternalId);
        });
    });

    describe('getUserStats', () => {
        let instanceId: number;

        beforeEach(() => {
            instanceId = fakePositiveInteger();
        });

        it('should list users if one exist', async () => {
            const countUsers = fakePositiveInteger();

            usersService.getCountOfUsersByStatus.mockResolvedValueOnce(countUsers);

            const result = await usersAdapter.getCountOfUsersByStatus(instanceId, [UserStatus.ACTIVE, UserStatus.UNCLAIMED]);

            expect(result).toBe(countUsers);
        });
    });

    describe('listAll', () => {
        let user: UserDAO;
        let filters: UserListAllFilters;
        let options: ListOptions;

        beforeEach(() => {
            user = new UserDAO();
            user.id = fakePositiveInteger();

            user.firstName = faker.person.firstName();
            user.lastName = faker.person.lastName();
            user.employeeInternalId = faker.word.noun();
            filters = {};
            options = { pagination: { limit: 10, offset: 0 } };
        });

        it('should return empty if no users exist', async () => {
            usersService.listAll.mockResolvedValueOnce({ count: 0, rows: [] });

            const result = await usersAdapter.listAll(user, filters, options);

            expect(result.count).toBe(0);
            expect(result.rows).toHaveLength(0);
        });

        it('should list users if one exist', async () => {
            usersService.listAll.mockResolvedValueOnce({ count: 1, rows: [user] });

            const result = await usersAdapter.listAll(user, filters, options);

            expect(result.count).toBe(1);
            expect(result.rows[0].firstName).toBe(user.firstName);
            expect(result.rows[0].lastName).toBe(user.lastName);
            expect(result.rows[0].id).toBe(user.id);
            expect(result.rows[0].employeeInternalId).toBe(user.employeeInternalId);
        });
    });

    describe('getSubordinateIds', () => {
        let userId: number;
        let instanceId: number;
        let subordinateIds: number[];

        beforeEach(() => {
            userId = fakePositiveInteger();
            instanceId = fakePositiveInteger();
        });

        it('should return user if one exist', async () => {
            subordinateIds = [fakePositiveInteger()];
            organizationChartsService.getSubordinateIds.mockResolvedValueOnce(subordinateIds);

            const result = await usersAdapter.getSubordinateIds(instanceId, userId);

            expect(result).toBeArrayOfSize(1);
            expect(result[0]).toBe(subordinateIds[0]);
        });
    });
});
