import { faker } from '@faker-js/faker/locale/en_US';
import { PerformanceReviewCycleReviewedUsersMode } from '../../../../src/api/modules/performanceReviews/business/types/performanceReviewCycleReviewedUsersMode';
import { PerformanceReviewCycleStatus } from '../../../../src/api/modules/performanceReviews/business/types/performanceReviewCycleStatus';
import { PerformanceReviewEvaluationTypes } from '../../../../src/api/modules/performanceReviews/business/types/performanceReviewEvaluationTypes';
import { UpdatePerformanceReviewCycleVC } from '../../../../src/api/modules/performanceReviews/presentation/validationClasses/updatePerformanceReviewCycleVC';
import { fakePositiveInteger } from '../../../common/common';
import { getValidationClass } from '../../../common/serializationClasses/serializationClassesHelper';

describe('UpdatePerformanceReviewCycleVC', () => {
    it(`should pass validation if the user sends correct parameters`, () => {
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates: [],
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewsVisibleAfterFinishedReviewCycle: false,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
            },
            UpdatePerformanceReviewCycleVC,
        );

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

    it(`should pass validation if the user sends correct parameters with one form template`, () => {
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates: [
                    {
                        evaluationType: faker.helpers.arrayElement(Object.values(PerformanceReviewEvaluationTypes)),
                        formTemplateId: fakePositiveInteger(),
                    },
                ],
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewsVisibleAfterFinishedReviewCycle: true,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
            },
            UpdatePerformanceReviewCycleVC,
        );

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

    it(`should pass validation if the user sends correct parameters with multiple form templates with same form template id`, () => {
        const formTemplateId = fakePositiveInteger();
        const evaluationTypes = faker.helpers.arrayElements(Object.values(PerformanceReviewEvaluationTypes));
        const formTemplates = evaluationTypes.map((evaluationType) => ({
            evaluationType,
            formTemplateId,
        }));
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates,
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewsVisibleAfterFinishedReviewCycle: false,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
            },
            UpdatePerformanceReviewCycleVC,
        );

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

    it(`should pass validation if the user sends correct parameters with multiple form templates with different form template id`, () => {
        const evaluationTypes = faker.helpers.arrayElements(Object.values(PerformanceReviewEvaluationTypes));
        const formTemplates = evaluationTypes.map((evaluationType) => ({
            evaluationType,
            formTemplateId: fakePositiveInteger(),
        }));
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates,
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewsVisibleAfterFinishedReviewCycle: false,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
            },
            UpdatePerformanceReviewCycleVC,
        );

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

    it('should validate correctly if the user sends an empty object', () => {
        const { errors } = getValidationClass({}, UpdatePerformanceReviewCycleVC);

        ['name', 'status', 'reviewedUsersMode', 'formTemplates'].forEach((property) => {
            expect(errors).toPartiallyContain({ property });
        });
    });

    it('should validate correctly if the user sends incorrect types', () => {
        const { errors } = getValidationClass(
            {
                formTemplates: faker.word.words(),
                name: faker.datatype.boolean(),
                reviewedUsersMode: fakePositiveInteger(),
                status: faker.datatype.boolean(),
            },
            UpdatePerformanceReviewCycleVC,
        );

        ['name', 'status', 'reviewedUsersMode', 'formTemplates'].forEach((property) => {
            expect(errors).toPartiallyContain({ property });
        });
    });

    it(`should validate correctly if the user sends incorrect status`, () => {
        const { errors } = getValidationClass(
            {
                formTemplates: [],
                name: faker.word.words(),
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                status: faker.word.words(),
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toPartiallyContain({ property: 'status' });
    });

    it(`should validate correctly if the user sends in progress status`, () => {
        const { errors } = getValidationClass(
            {
                formTemplates: [],
                name: faker.word.words(),
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                status: PerformanceReviewCycleStatus.IN_PROGRESS,
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toPartiallyContain({ property: 'status' });
    });

    it(`should validate correctly if the user sends finished status`, () => {
        const { errors } = getValidationClass(
            {
                formTemplates: [],
                name: faker.word.words(),
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                status: PerformanceReviewCycleStatus.FINISHED,
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toPartiallyContain({ property: 'status' });
    });

    it(`should validate correctly if the user sends incorrect reviewed users mode`, () => {
        const { errors } = getValidationClass(
            {
                formTemplates: [],
                name: faker.word.words(),
                reviewedUsersMode: faker.word.words(),
                status: faker.helpers.arrayElement([PerformanceReviewCycleStatus.DRAFT, PerformanceReviewCycleStatus.PENDING]),
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toPartiallyContain({ property: 'reviewedUsersMode' });
    });

    it(`should validate correctly if the user sends incorrect form templates`, () => {
        const { errors } = getValidationClass(
            {
                formTemplates: [
                    {
                        property: faker.word.words(),
                        secondProperty: fakePositiveInteger(),
                    },
                ],
                name: faker.word.words(),
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                status: faker.helpers.arrayElement([PerformanceReviewCycleStatus.DRAFT, PerformanceReviewCycleStatus.PENDING]),
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toPartiallyContain({ property: 'formTemplates' });
    });

    it(`should validate correctly if the user sends duplicate form template evaluation types`, () => {
        const evaluationType = faker.helpers.arrayElement(Object.values(PerformanceReviewEvaluationTypes));
        const { errors } = getValidationClass(
            {
                formTemplates: [
                    {
                        evaluationType: evaluationType,
                        formTemplateId: fakePositiveInteger(),
                    },
                    {
                        evaluationType: evaluationType,
                        formTemplateId: fakePositiveInteger(),
                    },
                ],
                name: faker.word.words(),
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                status: faker.helpers.arrayElement([PerformanceReviewCycleStatus.DRAFT, PerformanceReviewCycleStatus.PENDING]),
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toPartiallyContain({ property: 'formTemplates' });
    });

    it(`should validate correctly if the user sends the correct withSummary`, () => {
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates: [],
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewsVisibleAfterFinishedReviewCycle: false,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
                withSummary: 'true',
            },
            UpdatePerformanceReviewCycleVC,
        );

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

    it(`should validate correctly if the user sends another type different than boolean as withSummary`, () => {
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates: [],
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewsVisibleAfterFinishedReviewCycle: false,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
                withSummary: 1 as unknown as boolean,
            },
            UpdatePerformanceReviewCycleVC,
        );

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

    it(`should validate correctly if the user sends wrong type as reviewerLimitByHiringDate`, () => {
        const { errors } = getValidationClass(
            {
                canBeShared: true,
                formTemplates: [],
                name: faker.word.words(),
                peerReviewReviewerSelectionVisibleForBosses: false,
                reviewedUsersMode: faker.helpers.arrayElement(Object.values(PerformanceReviewCycleReviewedUsersMode)),
                reviewerLimitByHiringDate: faker.number,
                reviewsVisibleAfterFinishedReviewCycle: false,
                status: faker.helpers.arrayElement([
                    PerformanceReviewCycleStatus.DRAFT,
                    PerformanceReviewCycleStatus.SELECTION,
                    PerformanceReviewCycleStatus.PENDING,
                ]),
            },
            UpdatePerformanceReviewCycleVC,
        );

        expect(errors).toHaveLength(1);
    });
});
