import { faker } from '@faker-js/faker/locale/en_US';
import {
    PerformanceReviewEvaluationTypes,
    PerformanceReviewEvaluationTypesValues,
} from '../../../../src/api/modules/performanceReviews/business/types/performanceReviewEvaluationTypes';
import {
    PerformanceReviewFormStatus,
    PerformanceReviewFormStatusValues,
} from '../../../../src/api/modules/performanceReviews/business/types/performanceReviewFormStatus';
import { PerformanceReviewFormReviewsStatsSC } from '../../../../src/api/modules/performanceReviews/presentation/serializationClasses/performanceReviewFormReviewsStatsSC';
import { generateRandomReviewCountsForTypesAndStatuses } from '../common';

describe('PerformanceReviewFormReviewsStatsSC', () => {
    it('should serialize reviewed users stats', () => {
        const types = faker.helpers.arrayElements(Object.values(PerformanceReviewEvaluationTypes), {
            max: Object.values(PerformanceReviewEvaluationTypes).length,
            min: 1,
        }) as PerformanceReviewEvaluationTypesValues[];
        const statuses = Object.values(PerformanceReviewFormStatus);
        const stats = generateRandomReviewCountsForTypesAndStatuses(types, statuses);

        const serializedStats = new PerformanceReviewFormReviewsStatsSC().serialize({ statsPerEvaluationType: stats, withScore: true });
        const expectedTotalPerStatus = statuses.reduce((records, status) => {
            records[status] = 0;
            return records;
        }, {} as { [key in PerformanceReviewFormStatusValues]: number });

        expect(serializedStats).not.toBeNull();
        expect(Object.keys(serializedStats.statsPerEvaluationType)).toHaveLength(types.length);

        Object.keys(serializedStats.statsPerEvaluationType).forEach((type) => {
            expect(Object.keys(serializedStats.statsPerEvaluationType[type as PerformanceReviewEvaluationTypesValues])).toHaveLength(statuses.length);

            Object.keys(serializedStats.statsPerEvaluationType[type as PerformanceReviewEvaluationTypesValues]).forEach((status) => {
                expect(serializedStats.statsPerEvaluationType[type as PerformanceReviewEvaluationTypesValues][status]).toBeNumber();

                expectedTotalPerStatus[status] =
                    expectedTotalPerStatus[status] + serializedStats.statsPerEvaluationType[type as PerformanceReviewEvaluationTypesValues][status];
            });
        });

        expect(Object.keys(serializedStats.totalStats)).toHaveLength(statuses.length);

        Object.keys(serializedStats.totalStats).forEach((status) => {
            expect(serializedStats.totalStats[status]).toBe(expectedTotalPerStatus[status]);
        });
    });

    it('should serialize with team stats', () => {
        const types = [PerformanceReviewEvaluationTypes.AUTO_REVIEW] as PerformanceReviewEvaluationTypesValues[];
        const statuses = Object.values(PerformanceReviewFormStatus);
        const stats = generateRandomReviewCountsForTypesAndStatuses(types, statuses);

        const teamStats = {
            teamScore: 93.5,
            evaluatedCollaborators: 3,
            totalCollaborators: 15,
            deliveredEvaluations: 2,
            statusBreakdown: { finished: 3, inProgress: 5, pending: 7 },
        };

        const serializedStats = new PerformanceReviewFormReviewsStatsSC().serialize({ statsPerEvaluationType: stats, teamStats, withScore: true });

        expect(serializedStats.teamScore).toBe(93.5);
        expect(serializedStats.evaluatedCollaborators).toBe(3);
        expect(serializedStats.totalCollaborators).toBe(15);
        expect(serializedStats.deliveredEvaluations).toBe(2);
        expect(serializedStats.statusBreakdown).toEqual({ finished: 3, inProgress: 5, pending: 7 });
    });

    it('should omit team stat fields when teamStats is not provided', () => {
        const types = [PerformanceReviewEvaluationTypes.AUTO_REVIEW] as PerformanceReviewEvaluationTypesValues[];
        const statuses = Object.values(PerformanceReviewFormStatus);
        const stats = generateRandomReviewCountsForTypesAndStatuses(types, statuses);

        const serializedStats = new PerformanceReviewFormReviewsStatsSC().serialize({ statsPerEvaluationType: stats, withScore: false });

        expect(serializedStats).not.toHaveProperty('teamScore');
        expect(serializedStats).not.toHaveProperty('evaluatedCollaborators');
        expect(serializedStats).not.toHaveProperty('totalCollaborators');
        expect(serializedStats).not.toHaveProperty('deliveredEvaluations');
        expect(serializedStats).not.toHaveProperty('statusBreakdown');
        expect(serializedStats.statsPerEvaluationType).toBeDefined();
        expect(serializedStats.totalStats).toBeDefined();
        expect(serializedStats.withScore).toBe(false);
    });
});
