/*!
 * Copyright © 2016-2018 European Support Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
import deepFreeze from 'deep-freeze';
import mockRest from 'test-utils/MockRest.js';
import { cloneAndSet, buildListFromFactory } from 'test-utils/Util.js';
import { storeCreator } from 'sdc-app/AppStore.js';
import {
    LicenseKeyGroupStoreFactory,
    LicenseKeyGroupPostFactory
} from 'test-utils/factories/licenseModel/LicenseKeyGroupFactories.js';

import LicenseKeyGroupsActionHelper from 'sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js';
import VersionFactory from 'test-utils/factories/common/VersionFactory.js';
import CurrentScreenFactory from 'test-utils/factories/common/CurrentScreenFactory.js';
import {
    LimitItemFactory,
    LimitPostFactory
} from 'test-utils/factories/licenseModel/LimitFactories.js';
import { getStrValue } from 'nfvo-utils/getValue.js';
import { SyncStates } from 'sdc-app/common/merge/MergeEditorConstants.js';

describe('License Key Groups Module Tests', function() {
    const LICENSE_MODEL_ID = '555';
    const version = VersionFactory.build();
    const itemPermissionAndProps = CurrentScreenFactory.build({}, { version });
    const returnedVersionFields = {
        baseId: version.baseId,
        description: version.description,
        id: version.id,
        name: version.name,
        status: version.status
    };

    it('Load License Key Group', () => {
        const licenseKeyGroupsList = buildListFromFactory(
            LicenseKeyGroupStoreFactory
        );

        deepFreeze(licenseKeyGroupsList);
        const store = storeCreator();
        deepFreeze(store.getState());

        const expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsList',
            licenseKeyGroupsList
        );

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: licenseKeyGroupsList };
        });

        return LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(
            store.dispatch,
            { licenseModelId: LICENSE_MODEL_ID, version }
        ).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Delete License Key Group', () => {
        const licenseKeyGroupsList = buildListFromFactory(
            LicenseKeyGroupStoreFactory,
            1
        );

        deepFreeze(licenseKeyGroupsList);
        const store = storeCreator({
            currentScreen: { ...itemPermissionAndProps },
            licenseModel: {
                licenseKeyGroup: {
                    licenseKeyGroupsList
                }
            }
        });
        deepFreeze(store.getState());
        const toBeDeletedLicenseKeyGroupId = licenseKeyGroupsList[0].id;

        const expectedCurrentScreenProps = {
            ...itemPermissionAndProps,
            itemPermission: {
                ...itemPermissionAndProps.itemPermission,
                isDirty: true
            }
        };

        let expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsList',
            []
        );
        expectedStore = cloneAndSet(
            expectedStore,
            'currentScreen.itemPermission',
            expectedCurrentScreenProps.itemPermission
        );

        mockRest.addHandler('destroy', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${toBeDeletedLicenseKeyGroupId}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields,
                state: {
                    synchronizationState: SyncStates.UP_TO_DATE,
                    dirty: true
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: [] };
        });

        return LicenseKeyGroupsActionHelper.deleteLicenseKeyGroup(
            store.dispatch,
            {
                licenseKeyGroupId: toBeDeletedLicenseKeyGroupId,
                licenseModelId: LICENSE_MODEL_ID,
                version
            }
        ).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Add License Key Group', () => {
        const store = storeCreator({
            currentScreen: { ...itemPermissionAndProps }
        });
        deepFreeze(store.getState());

        const LicenseKeyGroupPost = LicenseKeyGroupPostFactory.build();
        deepFreeze(LicenseKeyGroupPost);

        const LicenseKeyGroupStore = LicenseKeyGroupStoreFactory.build();
        deepFreeze(LicenseKeyGroupStore);

        const expectedCurrentScreenProps = {
            ...itemPermissionAndProps,
            itemPermission: {
                ...itemPermissionAndProps.itemPermission,
                isDirty: true
            }
        };

        let expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsList',
            [LicenseKeyGroupStore]
        );
        expectedStore = cloneAndSet(
            expectedStore,
            'currentScreen.itemPermission',
            expectedCurrentScreenProps.itemPermission
        );

        mockRest.addHandler('post', ({ options, data, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups`
            );
            expect(data).toEqual(LicenseKeyGroupPost);
            expect(options).toEqual(undefined);
            return {
                value: LicenseKeyGroupStore.id
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields,
                state: {
                    synchronizationState: SyncStates.UP_TO_DATE,
                    dirty: true
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: [LicenseKeyGroupStore] };
        });

        return LicenseKeyGroupsActionHelper.saveLicenseKeyGroup(
            store.dispatch,
            {
                licenseKeyGroup: LicenseKeyGroupPost,
                licenseModelId: LICENSE_MODEL_ID,
                version
            }
        ).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Update License Key Group', () => {
        const licenseKeyGroupsList = buildListFromFactory(
            LicenseKeyGroupStoreFactory,
            1
        );
        deepFreeze(licenseKeyGroupsList);
        const store = storeCreator({
            currentScreen: { ...itemPermissionAndProps },
            licenseModel: {
                licenseKeyGroup: {
                    licenseKeyGroupsList
                }
            }
        });

        const toBeUpdatedLicenseKeyGroupId = licenseKeyGroupsList[0].id;
        const previousLicenseKeyGroupData = licenseKeyGroupsList[0];

        const licenseKeyGroupUpdatedData = LicenseKeyGroupPostFactory.build({
            name: 'lsk1_UPDATE',
            description: 'string_UPDATE',
            id: toBeUpdatedLicenseKeyGroupId
        });
        deepFreeze(licenseKeyGroupUpdatedData);

        const licenseKeyGroupPutRequest = LicenseKeyGroupPostFactory.build({
            name: 'lsk1_UPDATE',
            description: 'string_UPDATE'
        });

        deepFreeze(licenseKeyGroupPutRequest);

        const expectedCurrentScreenProps = {
            ...itemPermissionAndProps,
            itemPermission: {
                ...itemPermissionAndProps.itemPermission,
                isDirty: true
            }
        };

        let expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsList',
            [licenseKeyGroupUpdatedData]
        );
        expectedStore = cloneAndSet(
            expectedStore,
            'currentScreen.itemPermission',
            expectedCurrentScreenProps.itemPermission
        );

        mockRest.addHandler('put', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${toBeUpdatedLicenseKeyGroupId}`
            );
            expect(data).toEqual(licenseKeyGroupPutRequest);
            expect(options).toEqual(undefined);
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields,
                state: {
                    synchronizationState: SyncStates.UP_TO_DATE,
                    dirty: true
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: [licenseKeyGroupUpdatedData] };
        });

        return LicenseKeyGroupsActionHelper.saveLicenseKeyGroup(
            store.dispatch,
            {
                previousLicenseKeyGroup: previousLicenseKeyGroupData,
                licenseKeyGroup: licenseKeyGroupUpdatedData,
                licenseModelId: LICENSE_MODEL_ID,
                version
            }
        ).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Load Limits List', () => {
        const limitsList = LimitItemFactory.buildList(3);
        deepFreeze(limitsList);
        const store = storeCreator();
        deepFreeze(store.getState());

        const expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsEditor.limitsList',
            limitsList
        );
        const licenseKeyGroup = LicenseKeyGroupStoreFactory.build();
        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: limitsList };
        });

        return LicenseKeyGroupsActionHelper.fetchLimits(store.dispatch, {
            licenseModelId: LICENSE_MODEL_ID,
            version,
            licenseKeyGroup
        }).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Add Limit', () => {
        const store = storeCreator({
            currentScreen: { ...itemPermissionAndProps }
        });
        deepFreeze(store.getState());

        const limitToAdd = LimitPostFactory.build();
        let limitFromBE = { ...limitToAdd };
        limitFromBE.metric = getStrValue(limitFromBE.metric);
        limitFromBE.unit = getStrValue(limitFromBE.unit);

        deepFreeze(limitToAdd);
        deepFreeze(limitFromBE);

        const LimitIdFromResponse = 'ADDED_ID';
        const limitAddedItem = { ...limitToAdd, id: LimitIdFromResponse };
        deepFreeze(limitAddedItem);
        const licenseKeyGroup = LicenseKeyGroupStoreFactory.build();

        const expectedCurrentScreenProps = {
            ...itemPermissionAndProps,
            itemPermission: {
                ...itemPermissionAndProps.itemPermission,
                isDirty: true
            }
        };

        let expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsEditor.limitsList',
            [limitAddedItem]
        );
        expectedStore = cloneAndSet(
            expectedStore,
            'currentScreen.itemPermission',
            expectedCurrentScreenProps.itemPermission
        );

        mockRest.addHandler('post', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits`
            );
            expect(data).toEqual(limitFromBE);
            expect(options).toEqual(undefined);
            return {
                returnCode: 'OK',
                value: LimitIdFromResponse
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: [limitAddedItem] };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields,
                state: {
                    synchronizationState: SyncStates.UP_TO_DATE,
                    dirty: true
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields
            };
        });

        return LicenseKeyGroupsActionHelper.submitLimit(store.dispatch, {
            licenseModelId: LICENSE_MODEL_ID,
            version,
            licenseKeyGroup,
            limit: limitToAdd
        }).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Delete Limit', () => {
        const limitsList = LimitItemFactory.buildList(1);
        deepFreeze(limitsList);

        const store = storeCreator({
            currentScreen: { ...itemPermissionAndProps },
            licenseModel: {
                entitlementPool: {
                    entitlementPoolEditor: {
                        limitsList
                    }
                }
            }
        });
        deepFreeze(store.getState());

        const licenseKeyGroup = LicenseKeyGroupStoreFactory.build();

        const expectedCurrentScreenProps = {
            ...itemPermissionAndProps,
            itemPermission: {
                ...itemPermissionAndProps.itemPermission,
                isDirty: true
            }
        };

        let expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsEditor.limitsList',
            []
        );
        expectedStore = cloneAndSet(
            expectedStore,
            'currentScreen.itemPermission',
            expectedCurrentScreenProps.itemPermission
        );

        mockRest.addHandler('destroy', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits/${
                    limitsList[0].id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                results: {
                    returnCode: 'OK'
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: [] };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields,
                state: {
                    synchronizationState: SyncStates.UP_TO_DATE,
                    dirty: true
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields
            };
        });

        return LicenseKeyGroupsActionHelper.deleteLimit(store.dispatch, {
            licenseModelId: LICENSE_MODEL_ID,
            version,
            licenseKeyGroup,
            limit: limitsList[0]
        }).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });

    it('Update Limit', () => {
        const limitsList = LimitItemFactory.buildList(1);
        deepFreeze(limitsList);
        const licenseKeyGroup = LicenseKeyGroupStoreFactory.build();
        const store = storeCreator({
            currentScreen: { ...itemPermissionAndProps },
            licenseModel: {
                licenseKeyGroup: {
                    licenseKeyGroupsEditor: {
                        limitsList
                    }
                }
            }
        });

        deepFreeze(store.getState());

        const previousData = limitsList[0];
        deepFreeze(previousData);
        const limitId = limitsList[0].id;

        let updatedLimit = { ...previousData, name: 'updatedLimit' };
        const updatedLimitForPut = { ...updatedLimit, id: undefined };
        updatedLimit.metric = { choice: updatedLimit.metric, other: '' };
        updatedLimit.unit = { choice: updatedLimit.unit, other: '' };
        deepFreeze(updatedLimit);

        const expectedCurrentScreenProps = {
            ...itemPermissionAndProps,
            itemPermission: {
                ...itemPermissionAndProps.itemPermission,
                isDirty: true
            }
        };

        let expectedStore = cloneAndSet(
            store.getState(),
            'licenseModel.licenseKeyGroup.licenseKeyGroupsEditor.limitsList',
            [updatedLimitForPut]
        );
        expectedStore = cloneAndSet(
            expectedStore,
            'currentScreen.itemPermission',
            expectedCurrentScreenProps.itemPermission
        );

        mockRest.addHandler('put', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits/${limitId}`
            );
            expect(data).toEqual(updatedLimitForPut);
            expect(options).toEqual(undefined);
            return { returnCode: 'OK' };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/vendor-license-models/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }/license-key-groups/${licenseKeyGroup.id}/limits`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return { results: [updatedLimitForPut] };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}/versions/${
                    version.id
                }`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields,
                state: {
                    synchronizationState: SyncStates.UP_TO_DATE,
                    dirty: true
                }
            };
        });

        mockRest.addHandler('fetch', ({ data, options, baseUrl }) => {
            expect(baseUrl).toEqual(
                `/onboarding-api/v1.0/items/${LICENSE_MODEL_ID}`
            );
            expect(data).toEqual(undefined);
            expect(options).toEqual(undefined);
            return {
                ...returnedVersionFields
            };
        });

        return LicenseKeyGroupsActionHelper.submitLimit(store.dispatch, {
            licenseModelId: LICENSE_MODEL_ID,
            version,
            licenseKeyGroup,
            limit: updatedLimit
        }).then(() => {
            expect(store.getState()).toEqual(expectedStore);
        });
    });
});