/*!
 * 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 { connect } from 'react-redux';

import i18n from 'nfvo-utils/i18n/i18n.js';
import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js';
import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx';

import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js';
import {
    onboardingMethod as onboardingMethodTypes,
    onboardingOriginTypes
} from './SoftwareProductConstants.js';
import SoftwareProductActionHelper from './SoftwareProductActionHelper.js';
import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
import PermissionsActionHelper from './../permissions/PermissionsActionHelper.js';
import RevisionsActionHelper from './../revisions/RevisionsActionHelper.js';
import HeatSetupActionHelper from './attachments/setup/HeatSetupActionHelper.js';
import { actionsEnum as versionControllerActions } from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js';
import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js';
import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx';
import { onboardingMethod as onboardingMethodType } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
import { SyncStates } from 'sdc-app/common/merge/MergeEditorConstants.js';
import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js';

function getActiveNavigationId(screen, componentId) {
    let activeItemId = componentId ? screen + '|' + componentId : screen;
    return activeItemId;
}

const buildComponentNavigationBarGroups = ({ componentId, meta }) => {
    const groups = [
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL +
                '|' +
                componentId,
            name: i18n('General'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE +
                '|' +
                componentId,
            name: i18n('Compute'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING +
                '|' +
                componentId,
            name: i18n('High Availability & Load Balancing'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK +
                '|' +
                componentId,
            name: i18n('Networks'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE +
                '|' +
                componentId,
            name: i18n('Storage'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES +
                '|' +
                componentId,
            name: i18n('Images'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES +
                '|' +
                componentId,
            name: i18n('Process Details'),
            disabled: false,
            meta
        },
        {
            id:
                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING +
                '|' +
                componentId,
            name: i18n('Monitoring'),
            disabled: false,
            meta
        }
    ];

    return groups;
};

const buildNavigationBarProps = ({
    softwareProduct,
    meta,
    screen,
    componentId,
    componentsList,
    mapOfExpandedIds,
    isCertified
}) => {
    const {
        softwareProductEditor: { data: currentSoftwareProduct = {} }
    } = softwareProduct;
    const {
        id,
        name,
        onboardingMethod,
        candidateOnboardingOrigin,
        onboardingOrigin
    } = currentSoftwareProduct;
    const groups = [
        {
            id: id,
            name: name,
            items: [
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
                    name: i18n('Overview'),
                    disabled: false,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_DETAILS,
                    name: i18n('General'),
                    disabled: false,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT,
                    name: i18n('Deployment Flavors'),
                    disabled: false,
                    hidden: onboardingMethod !== onboardingMethodTypes.MANUAL,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES,
                    name: i18n('Process Details'),
                    disabled: false,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS,
                    name: i18n('Networks'),
                    disabled: false,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS,
                    name: i18n('Attachments'),
                    disabled: false,
                    hidden: !candidateOnboardingOrigin && !onboardingOrigin,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG,
                    name: i18n('Activity Log'),
                    disabled: false,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES,
                    name: i18n('Component Dependencies'),
                    hidden: componentsList.length <= 1,
                    disabled: false,
                    meta
                },
                {
                    id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS,
                    name: i18n('Components'),
                    hidden: componentsList.length <= 0,
                    meta,
                    expanded:
                        mapOfExpandedIds[
                            enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS
                        ] === true &&
                        screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
                    items: [
                        ...componentsList.map(({ id, displayName }) => ({
                            id:
                                enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS +
                                '|' +
                                id,
                            name: displayName,
                            meta,
                            expanded:
                                mapOfExpandedIds[
                                    enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS +
                                        '|' +
                                        id
                                ] === true &&
                                screen !==
                                    enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
                            items: buildComponentNavigationBarGroups({
                                componentId: id,
                                meta
                            })
                        }))
                    ]
                }
            ]
        }
    ];
    let activeItemId = getActiveNavigationId(screen, componentId);
    return {
        activeItemId,
        groups,
        disabled: !!candidateOnboardingOrigin && !isCertified
    };
};

const buildVersionControllerProps = ({
    softwareProduct,
    versions,
    currentVersion,
    permissions,
    userInfo,
    isArchived,
    usersList,
    itemPermission,
    isReadOnlyMode
}) => {
    const { softwareProductEditor = { data: {} } } = softwareProduct;
    const {
        isValidityData = true,
        data: { name, onboardingMethod, candidateOnboardingOrigin }
    } = softwareProductEditor;

    return {
        version: currentVersion,
        viewableVersions: versions,
        isFormDataValid: isValidityData,
        permissions,
        itemName: name,
        itemPermission,
        isReadOnlyMode,
        isArchived,
        userInfo,
        usersList,
        isManual: onboardingMethod === onboardingMethodType.MANUAL,
        candidateInProcess:
            !!candidateOnboardingOrigin && !itemPermission.isCertified
    };
};

function buildMeta({
    softwareProduct,
    componentId,
    softwareProductDependencies,
    isReadOnlyMode
}) {
    const {
        softwareProductEditor,
        softwareProductComponents,
        softwareProductQuestionnaire,
        softwareProductAttachments
    } = softwareProduct;
    const { data: currentSoftwareProduct = {} } = softwareProductEditor;
    const {
        version,
        onboardingOrigin,
        candidateOnboardingOrigin
    } = currentSoftwareProduct;
    const { qdata } = softwareProductQuestionnaire;
    const { heatSetup, heatSetupCache } = softwareProductAttachments;
    let currentComponentMeta = {};
    if (componentId) {
        const {
            componentEditor: { data: componentData = {}, qdata: componentQdata }
        } = softwareProductComponents;
        currentComponentMeta = { componentData, componentQdata };
    }
    const meta = {
        softwareProduct: currentSoftwareProduct,
        qdata,
        version,
        onboardingOrigin,
        candidateOnboardingOrigin,
        heatSetup,
        heatSetupCache,
        isReadOnlyMode,
        currentComponentMeta,
        softwareProductDependencies
    };
    return meta;
}

const mapStateToProps = (
    {
        softwareProduct,
        users: { usersList, userInfo },
        versionsPage: { versionsList: { versions }, permissions }
    },
    {
        currentScreen: {
            screen,
            itemPermission,
            props: { version: currentVersion, componentId, isReadOnlyMode }
        }
    }
) => {
    const {
        softwareProductEditor,
        softwareProductComponents,
        softwareProductDependencies
    } = softwareProduct;
    const { mapOfExpandedIds = [] } = softwareProductEditor;
    const { componentsList = [] } = softwareProductComponents;

    const meta = buildMeta({
        softwareProduct,
        componentId,
        softwareProductDependencies,
        isReadOnlyMode
    });
    return {
        versionControllerProps: buildVersionControllerProps({
            softwareProduct,
            versions,
            currentVersion,
            userInfo,
            usersList,
            isArchived: itemPermission.isArchived,
            permissions,
            itemPermission: { ...itemPermission, isDirty: true },
            isReadOnlyMode
        }),
        navigationBarProps: buildNavigationBarProps({
            softwareProduct,
            meta,
            screen,
            componentId,
            componentsList,
            mapOfExpandedIds,
            isCertified: itemPermission.isCertified
        }),
        meta
    };
};

const autoSaveBeforeNavigate = ({
    dispatch,
    screen,
    softwareProductId,
    version,
    componentId,
    meta: {
        isReadOnlyMode,
        softwareProduct,
        qdata,
        currentComponentMeta: { componentData, componentQdata }
    }
}) => {
    let promise;
    if (isReadOnlyMode) {
        promise = Promise.resolve();
    } else {
        switch (screen) {
            case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS:
                promise = SoftwareProductActionHelper.updateSoftwareProduct(
                    dispatch,
                    { softwareProduct, version, qdata }
                );
                break;
            case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL:
                promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponent(
                    dispatch,
                    {
                        softwareProductId,
                        version,
                        vspComponentId: componentId,
                        componentData,
                        qdata: componentQdata
                    }
                );
                break;
            case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE:
            case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE:
            case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK:
            case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES:
            case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING:
                promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(
                    dispatch,
                    {
                        softwareProductId,
                        version,
                        vspComponentId: componentId,
                        qdata: componentQdata
                    }
                );
                break;
            default:
                promise = Promise.resolve();
                break;
        }
    }
    return promise;
};

const mapActionsToProps = (
    dispatch,
    {
        currentScreen: {
            screen,
            props: {
                softwareProductId,
                licenseModelId,
                version,
                componentId: currentComponentId
            }
        }
    }
) => {
    const props = {
        onVersionSwitching: (versionToSwitch, meta) => {
            ScreensHelper.loadScreen(dispatch, {
                screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
                screenType: screenTypes.SOFTWARE_PRODUCT,
                props: {
                    softwareProductId: meta.softwareProduct.id,
                    version: versionToSwitch
                }
            });
        },
        onOpenPermissions: ({ users }) => {
            return PermissionsActionHelper.fetchItemUsers(dispatch, {
                itemId: softwareProductId,
                allUsers: users
            });
        },
        onOpenRevisionsModal: () => {
            return RevisionsActionHelper.openRevisionsView(dispatch, {
                itemId: softwareProductId,
                version: version,
                itemType: screenTypes.SOFTWARE_PRODUCT
            });
        },
        onOpenCommentCommitModal: ({ onCommit, title }) =>
            dispatch({
                type: modalActionTypes.GLOBAL_MODAL_SHOW,
                data: {
                    modalComponentName: modalContentMapper.COMMIT_COMMENT,
                    modalComponentProps: {
                        onCommit,
                        type: CommitModalType.COMMIT
                    },
                    title
                }
            }),
        onMoreVersionsClick: ({ itemName, users }) => {
            ScreensHelper.loadScreen(dispatch, {
                screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE,
                screenType: screenTypes.SOFTWARE_PRODUCT,
                props: {
                    softwareProductId,
                    softwareProduct: {
                        name: itemName,
                        vendorId: licenseModelId
                    },
                    usersList: users
                }
            });
        },
        onToggle: (groups, itemIdToExpand) =>
            groups.map(({ items }) =>
                SoftwareProductActionHelper.toggleNavigationItems(dispatch, {
                    items,
                    itemIdToExpand
                })
            ),
        onNavigate: ({ id, meta, newVersion }) => {
            let navigationVersion = newVersion || version;
            let {
                onboardingOrigin,
                candidateOnboardingOrigin,
                heatSetup,
                heatSetupCache
            } = meta;
            let heatSetupPopupPromise =
                screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS
                    ? HeatSetupActionHelper.heatSetupLeaveConfirmation(
                          dispatch,
                          { softwareProductId, heatSetup, heatSetupCache }
                      )
                    : Promise.resolve();
            let preNavigate = meta
                ? autoSaveBeforeNavigate({
                      dispatch,
                      screen,
                      meta,
                      version,
                      softwareProductId,
                      componentId: currentComponentId
                  })
                : Promise.resolve();
            version = version || (meta ? meta.version : undefined);
            Promise.all([preNavigate, heatSetupPopupPromise])
                .then(() => {
                    let [nextScreen, nextComponentId] = id.split('|');
                    if (
                        nextScreen ===
                            enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS &&
                        nextComponentId &&
                        nextComponentId === currentComponentId
                    ) {
                        ScreensHelper.loadScreen(dispatch, {
                            screen: nextScreen,
                            screenType: screenTypes.SOFTWARE_PRODUCT,
                            props: {
                                softwareProductId,
                                version: navigationVersion
                            }
                        });
                    } else {
                        if (
                            nextScreen ===
                            enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS
                        ) {
                            if (
                                onboardingOrigin ===
                                    onboardingOriginTypes.ZIP ||
                                candidateOnboardingOrigin ===
                                    onboardingOriginTypes.ZIP
                            ) {
                                nextScreen =
                                    enums.SCREEN
                                        .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP;
                            } else if (
                                onboardingOrigin === onboardingOriginTypes.CSAR
                            ) {
                                nextScreen =
                                    enums.SCREEN
                                        .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION;
                            }
                        }
                        ScreensHelper.loadScreen(dispatch, {
                            screen: nextScreen,
                            screenType: screenTypes.SOFTWARE_PRODUCT,
                            props: {
                                softwareProductId,
                                version: navigationVersion,
                                componentId: nextComponentId
                            }
                        });
                    }
                })
                .catch(e => {
                    console.error(e);
                });
        }
    };

    switch (screen) {
        case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE:
        case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS:
        case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES:
        case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS:
        case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES:
        case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG:
        case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS:
        case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT:
        case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES:
        case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING:
            props.onSave = () => Promise.resolve();
            break;
        default:
            props.onSave = ({ softwareProduct, qdata }) =>
                SoftwareProductActionHelper.updateSoftwareProduct(dispatch, {
                    softwareProduct,
                    qdata,
                    version
                });
            break;
    }

    props.onVersionControllerAction = (action, version, comment, meta) => {
        let { heatSetup, heatSetupCache } = meta;
        let autoSavePromise = meta
            ? autoSaveBeforeNavigate({
                  dispatch,
                  screen,
                  meta,
                  version,
                  softwareProductId,
                  componentId: currentComponentId
              })
            : Promise.resolve();
        let heatSetupPopupPromise =
            screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS &&
            action === versionControllerActions.COMMIT
                ? HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {
                      softwareProductId,
                      heatSetup,
                      heatSetupCache
                  })
                : Promise.resolve();
        Promise.all([autoSavePromise, heatSetupPopupPromise])
            .then(() => {
                return SoftwareProductActionHelper.performVCAction(dispatch, {
                    softwareProductId,
                    action,
                    version,
                    comment,
                    meta
                }).then(updatedVersion => {
                    const inMerge =
                        updatedVersion &&
                        updatedVersion.state &&
                        updatedVersion.state.synchronizationState ===
                            SyncStates.MERGE;
                    if (
                        (action === versionControllerActions.SYNC &&
                            !inMerge) ||
                        ((action === versionControllerActions.COMMIT ||
                            action === versionControllerActions.SYNC) &&
                            updatedVersion.status ===
                                catalogItemStatuses.CERTIFIED)
                    ) {
                        ScreensHelper.loadLandingScreen(dispatch, {
                            previousScreenName: screen,
                            props: {
                                softwareProductId,
                                version: updatedVersion
                            }
                        });
                    } else {
                        ScreensHelper.loadScreen(dispatch, {
                            screen,
                            screenType: screenTypes.SOFTWARE_PRODUCT,
                            props: {
                                softwareProductId,
                                version: updatedVersion,
                                componentId: currentComponentId
                            }
                        });
                    }
                });
            })
            .catch(e => {
                console.error(e);
            });
    };

    props.onManagePermissions = () =>
        PermissionsActionHelper.openPermissonsManager(dispatch, {
            itemId: softwareProductId,
            askForRights: false
        });
    return props;
};

export default connect(mapStateToProps, mapActionsToProps)(TabulatedEditor);