/**
 * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.com). All Rights Reserved.
 *
 * This software is the property of WSO2 Inc. and its suppliers, if any.
 * Dissemination of any information or reproduction of any material contained
 * herein in any form is strictly forbidden, unless permitted by WSO2 expressly.
 * You may not alter or remove any copyright or other notice from copies of this content."
 */

import { getRawDocumentation } from "@wso2is/core/api";
import { isFeatureEnabled } from "@wso2is/core/helpers";
import { AlertLevels } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import {
    EmphasizedSegment,
    LinkButton,
    Markdown,
    ResourceTab,
    Text
} from "@wso2is/react-components";
import _ from "lodash";
import React, { FunctionComponent, ReactElement, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { Divider, Grid, Icon } from "semantic-ui-react";
import { HelpPanelOverview } from "./overview";
import { SamplesGuideComponent } from "./samples-guide";
import { IntegrateAppComponent } from "./integrate";
import { TryoutComponentFactory } from "./tryout";
import {
    AppState,
    AppConstants,
    history,
    ConfigReducerStateInterface,
    DocPanelUICardInterface,
    FeatureConfigInterface,
    PortalDocumentationStructureInterface,
    setHelpPanelDocsContentURL,
    toggleHelpPanelVisibility
} from "../../../../features/core";
import {
    ApplicationInterface,
    ApplicationManagementConstants,
    ApplicationManagementUtils,
    ApplicationTemplateListItemInterface,
    ApplicationTemplateManagementUtils,
    emptyApplication,
    getApplicationDetails,
    updateApplicationConfigurations
} from "../../../../features/applications";

/**
 * A function returning a ReactElement to render tab panes.
 */
const QuickStart: FunctionComponent = (): ReactElement => {

    const { t } = useTranslation();

    const dispatch = useDispatch();

    const config: ConfigReducerStateInterface = useSelector((state: AppState) => state.config);
    const helpPanelDocURL: string = useSelector((state: AppState) => state.helpPanel.docURL);
    const helpPanelDocStructure: PortalDocumentationStructureInterface = useSelector(
        (state: AppState) => state.helpPanel.docStructure);
    const applicationTemplates: ApplicationTemplateListItemInterface[] = useSelector(
        (state: AppState) => state.application.templates);
    const featureConfig: FeatureConfigInterface = useSelector((state: AppState) => state.config.ui.features);

    const [ application, setApplication ] = useState<ApplicationInterface>(emptyApplication);
    const [ applicationTemplateName, setApplicationTemplateName ] = useState<string>(undefined);
    const [ applicationTemplate, setApplicationTemplate ] = useState<ApplicationTemplateListItemInterface>(undefined);
    const [ isApplicationRequestLoading, setApplicationRequestLoading ] = useState<boolean>(false);
    const [ helpPanelDocContent, setHelpPanelDocContent ] = useState<string>(undefined);
    const [ helpPanelSampleContent, setHelpPanelSampleContent ] = useState<string>(undefined);
    const [ helpPanelSDKContent, setHelpPanelSDKContent ] = useState<string>(undefined);
    const [ helpPanelConfigContent, setHelpPanelConfigContent ] = useState<string>(undefined);
    const [ helpPanelSelectedSDK, setHelpPanelSelectedSDK ] = useState<DocPanelUICardInterface>(undefined);
    const [ helpPanelSelectedSample, setHelpPanelSelectedSample ] = useState<DocPanelUICardInterface>(undefined);
    const [
        helpPanelSelectedProtocol, setHelpPanelSelectedProtocol
    ] = useState<DocPanelUICardInterface>(undefined);
    const [ samplesTabBackButtonEnabled, setSamplesTabBackButtonEnabled ] = useState<boolean>(true);
    const [ samples, setSamples ] = useState<DocPanelUICardInterface[]>(undefined);
    const [ sdks, setSDKS ] = useState<DocPanelUICardInterface[]>(undefined);
    const [ configs, setConfigs ] = useState<DocPanelUICardInterface[]>(undefined);
    const [
        isHelpPanelDocContentRequestLoading,
        setHelpPanelDocContentRequestLoadingStatus
    ] = useState<boolean>(false);
    const [
        isHelpPanelSamplesContentRequestLoading,
        setHelpPanelSamplesContentRequestLoadingStatus
    ] = useState<boolean>(false);
    const [
        isApplicationTemplateRequestLoading,
        setApplicationTemplateRequestLoadingStatus
    ] = useState<boolean>(false);
    const [ selectedIntegration, setSelectedIntegration ] = useState<string>(undefined);

    const tocItemOneRef = useRef(null);
    const tocItemTwoRef = useRef(null);

    /**
     * Fetch the application details on initial component load.
     */
    useEffect(() => {
        if (applicationTemplates === undefined) {
            return;
        }

        const path = history.location.pathname.split("/");
        const id = path[ path.length - 1 ];

        getApplication(id);
    }, [ applicationTemplates ]);

    /**
     * Fetch the application details on initial component load.
     */
    useEffect(() => {
        if (!configs) {
            return;
        }

        configs.map((config) => {
            setHelpPanelSelectedProtocol(config);
        })
    }, [ configs ]);

    useEffect(() => {
        if (selectedIntegration === undefined) {
            setSelectedIntegration("INTEGRATE")
        }
    }, [])

    /**
     * Push to 404 if application edit feature is disabled.
     */
    useEffect(() => {
        if (!featureConfig || !featureConfig.applications) {
            return;
        }

        if(!isFeatureEnabled(featureConfig.applications,
            ApplicationManagementConstants.FEATURE_DICTIONARY.get("APPLICATION_EDIT"))) {

            history.push(AppConstants.getPaths().get("PAGE_NOT_FOUND"));
        }
    }, [ featureConfig ]);

    /**
     * Set the template once application templates list is available in redux.
     */
    useEffect(() => {
        if (applicationTemplates === undefined) {

            setApplicationTemplateRequestLoadingStatus(true);

            ApplicationTemplateManagementUtils.getApplicationTemplates()
                .finally(() => {
                    setApplicationTemplateRequestLoadingStatus(false);
                });

            return;
        }

        if (applicationTemplateName
            && !_.isEmpty(applicationTemplates)
            && applicationTemplates instanceof Array
            && applicationTemplates.length > 0) {

            setApplicationTemplate(applicationTemplates.find(
                (template) => template.name === applicationTemplateName));
        }
    }, [ applicationTemplateName, applicationTemplates ]);

    /**
     * Set the default doc content URL for the tab.
     */
    useEffect(() => {
        if (!applicationTemplateName) {
            return;
        }

        const editApplicationDocs = _.get(helpPanelDocStructure,
            ApplicationManagementConstants.EDIT_APPLICATIONS_DOCS_KEY);

        if (!editApplicationDocs) {
            return;
        }

        dispatch(setHelpPanelDocsContentURL(editApplicationDocs[
            ApplicationManagementConstants.APPLICATION_TEMPLATE_DOC_MAPPING
                .get(applicationTemplateName) ]?.[ApplicationManagementConstants.APPLICATION_DOCS_OVERVIEW]));
    }, [ applicationTemplateName, helpPanelDocStructure ]);

    /**
     * Filter application samples based on the template type.
     */
    useEffect(() => {
        if (!applicationTemplateName) {
            return;
        }
        const templateName = ApplicationManagementConstants.APPLICATION_TEMPLATE_DOC_MAPPING
            .get(applicationTemplateName);

        const samplesDocs = _.get(helpPanelDocStructure, ApplicationManagementUtils.getSampleDocsKey(templateName));
        const SDKDocs = _.get(helpPanelDocStructure, ApplicationManagementUtils.getSDKDocsKey(templateName));
        const configDocs = _.get(helpPanelDocStructure, ApplicationManagementUtils.getConfigDocsKey(templateName));

        if (!samplesDocs) {
            return;
        }

        const samples: DocPanelUICardInterface[] = ApplicationManagementUtils.generateSamplesAndSDKDocs(samplesDocs);
        const sdks: DocPanelUICardInterface[] = ApplicationManagementUtils.generateSamplesAndSDKDocs(SDKDocs);
        const configs: DocPanelUICardInterface[] = ApplicationManagementUtils.generateSamplesAndSDKDocs(configDocs);

        if (sdks instanceof Array && sdks.length === 1) {
            setHelpPanelSelectedSDK(sdks[ 0 ]);
            setSamplesTabBackButtonEnabled(false);
        }

        if (configs instanceof Array && configs.length === 1) {
            setHelpPanelSelectedProtocol(configs[ 0 ]);
            setSamplesTabBackButtonEnabled(false);
        }

        setSDKS(sdks.filter((item) => item.name !== "overview"));
        setSamples(samples.filter((item) => item.name !== "overview"));
        setConfigs(configs.filter((item) => item.name !== "overview"));
    }, [ applicationTemplateName, helpPanelDocStructure ]);

    /**
     * Called when help panel doc URL status changes.
     */
    useEffect(() => {
        if (!helpPanelDocURL) {
            return;
        }

        setHelpPanelDocContentRequestLoadingStatus(true);

        getRawDocumentation<string>(
            config?.endpoints?.documentationContent,
            helpPanelDocURL,
            config?.deployment?.documentation?.provider,
            config?.deployment?.documentation?.githubOptions?.branch)
            .then((response) => {
                setHelpPanelDocContent(response);
            })
            .finally(() => {
                setHelpPanelDocContentRequestLoadingStatus(false);
            });
    }, [ helpPanelDocURL ]);

    /**
     * Called when the technology is changed in the SDK section.
     */
    useEffect(() => {
        if (!helpPanelSelectedSDK?.docs) {
            return;
        }

        setHelpPanelSamplesContentRequestLoadingStatus(true);

        getRawDocumentation<string>(
            config.endpoints.documentationContent,
            helpPanelSelectedSDK.docs,
            config.deployment.documentation.provider,
            config.deployment.documentation.githubOptions.branch)
            .then((response) => {
                setHelpPanelSDKContent(response);
            })
            .finally(() => {
                setHelpPanelSamplesContentRequestLoadingStatus(false);
            });
    },[
        helpPanelSelectedSDK,
        config.deployment.documentation.githubOptions.branch,
        config.deployment.documentation.provider,
        config.endpoints.documentationContent
    ]);

    /**
     * Called when the technology is changed in the Configurations section.
     */
    useEffect(() => {
        if (!helpPanelSelectedProtocol?.docs) {
            return;
        }

        setHelpPanelSamplesContentRequestLoadingStatus(true);

        getRawDocumentation<string>(
            config.endpoints.documentationContent,
            helpPanelSelectedProtocol.docs,
            config.deployment.documentation.provider,
            config.deployment.documentation.githubOptions.branch)
            .then((response) => {
                setHelpPanelConfigContent(response);
            })
            .finally(() => {
                setHelpPanelSamplesContentRequestLoadingStatus(false);
            });
    },[
        helpPanelSelectedProtocol,
        config.deployment.documentation.githubOptions.branch,
        config.deployment.documentation.provider,
        config.endpoints.documentationContent
    ]);

    /**
     * Called when the technology is changed in the samples section.
     */
    useEffect(() => {
        if (!helpPanelSelectedSample?.docs) {
            return;
        }

        setHelpPanelSamplesContentRequestLoadingStatus(true);

        getRawDocumentation<string>(
            config.endpoints.documentationContent,
            helpPanelSelectedSample.docs,
            config.deployment.documentation.provider,
            config.deployment.documentation.githubOptions.branch)
            .then((response) => {
                setHelpPanelSampleContent(response);
            })
            .finally(() => {
                setHelpPanelSamplesContentRequestLoadingStatus(false);
            });
    },[
        helpPanelSelectedSample,
        config.deployment.documentation.githubOptions.branch,
        config.deployment.documentation.provider,
        config.endpoints.documentationContent
    ]);

    /**
     * Remove template name if multiple protocols configured.
     */
    useEffect(() => {
        if (applicationTemplateName && (application?.inboundProtocols?.length > 1)) {
            updateApplicationConfigurations(application.id, { description: application.description })
                .then(() => {
                    handleApplicationUpdate(application.id)
                })
                .catch((error) => {
                    if (error?.response?.status === 404) {
                        return;
                    }

                    if (error?.response && error?.response?.data && error?.response?.data?.description) {
                        dispatch(addAlert({
                            description: error.response?.data?.description,
                            level: AlertLevels.ERROR,
                            message: t("console:develop.features.applications.notifications.updateApplication" +
                                ".error.message")
                        }));

                        return;
                    }

                    dispatch(addAlert({
                        description: t("console:develop.features.applications.notifications.updateApplication" +
                            ".genericError.description"),
                        level: AlertLevels.ERROR,
                        message: t("console:develop.features.applications.notifications.updateApplication" +
                            ".genericError.message")
                    }));
                })
        }

    }, [applicationTemplateName, application]);

    /**
     * Retrieves application details from the API.
     *
     * @param {string} id - Application id.
     */
    const getApplication = (id: string): void => {
        setApplicationRequestLoading(true);

        getApplicationDetails(id)
            .then((response: ApplicationInterface) => {

                const template = applicationTemplates
                    && applicationTemplates instanceof Array
                    && applicationTemplates.length > 0
                    && applicationTemplates.find((template) => template.id === response.templateId);

                setApplicationTemplateName(template.name);

                setApplication(response);
            })
            .catch((error) => {
                if (error.response && error.response.data && error.response.data.description) {
                    dispatch(addAlert({
                        description: error.response.data.description,
                        level: AlertLevels.ERROR,
                        message: t("console:develop.features.applications.notifications.fetchApplication.error.message")
                    }));

                    return;
                }

                dispatch(addAlert({
                    description: t("console:develop.features.applications.notifications.fetchApplication" +
                        ".genericError.description"),
                    level: AlertLevels.ERROR,
                    message: t("console:develop.features.applications.notifications.fetchApplication.genericError." +
                        "message")
                }));
            })
            .finally(() => {
                setApplicationRequestLoading(false);
            });
    };

    /**
     * Handles help panel SDK change event.
     *
     * @param sdk - Selected SDK.
     */
    const handleHelpPanelSelectedSDK = (sdk: any) => {
        setHelpPanelSelectedSDK(sdk);
    };

    /**
     * Called when an application updates.
     *
     * @param {string} id - Application id.
     */
    const handleApplicationUpdate = (id: string): void => {
        getApplication(id);
    };

    /**
     * Handles help panel sample change event.
     *
     * @param sample - Selected sample.
     */
    const handleHelpPanelSelectedSample = (sample: any) => {
        setHelpPanelSelectedSample(sample);
    };

    const handleIntegrateSelection = (selection: string) => {
        setSelectedIntegration(selection);
    }

    const resolveDocContent = () => {
        if (helpPanelSelectedSDK || helpPanelSelectedSample) {
            if (helpPanelSelectedSDK) {
                return (
                    <>
                        <LinkButton className="pl-0"
                            onClick={ () => setHelpPanelSelectedSDK(undefined) }
                        >
                            <Icon name="arrow left"/>
                            Go back
                        </LinkButton>
                        <EmphasizedSegment>
                            <Markdown
                                source={ helpPanelSDKContent }
                            />
                        </EmphasizedSegment>

                    </>
                );
            } else {
                return (
                    <>
                        <LinkButton className="pl-0"
                            onClick={ () => setHelpPanelSelectedSample(undefined) }
                        >
                            <Icon name="arrow left"/>
                            Go back
                        </LinkButton>
                        <SamplesGuideComponent
                            sampleType={ helpPanelSelectedSample.name }
                            application={ application }
                            markDownSource={ helpPanelSampleContent }
                        />

                    </>
                );
            }
        } else {
            return (
                <>
                    <HelpPanelOverview
                        applicationType={ applicationTemplateName }
                        application={ application }
                        inboundProtocols={ application?.inboundProtocols }
                        handleIntegrateSelection={ handleIntegrateSelection }
                    />
                    <Divider hidden/>
                    { applicationTemplateName === "Web Application" ?
                        <Text muted>
                        Learn about Asgardio for web :
                            <LinkButton className="quick-start-action" compact>
                                View the docs
                                <Icon className="ml-1" name="external"/>
                            </LinkButton>
                        </Text>
                        :
                        <Text muted>
                            Learn about Asgardio for Single-Page Application :
                            <LinkButton className="quick-start-action" compact>
                                View the docs
                                <Icon className="ml-1" name="external"/>
                            </LinkButton>
                        </Text>
                    }
                    <Divider hidden/>
                    { selectedIntegration === "INTEGRATE"
                        ? <IntegrateAppComponent application={ application } applicationType={ applicationTemplateName } />
                        : <TryoutComponentFactory application={ application } template={ applicationTemplateName } />
                    }
                </>
            )
        }
    };

    return (
        <ResourceTab.Pane controlledSegmentation>
            <Grid>
                <Grid.Row>
                    <Grid.Column width={ 13 } >
                        { resolveDocContent() }
                    </Grid.Column>
                </Grid.Row>
            </Grid>
        </ResourceTab.Pane>
    );
};

export default QuickStart;
