/**
 * 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 React, { FunctionComponent, ReactElement, useState, useEffect } from "react";
import { CodeEditor } from "@wso2is/react-components";
import { Divider, Button, Message, Icon, Card } from "semantic-ui-react";
import {
    ApplicationInterface,
    SupportedAuthProtocolTypes,
    getInboundProtocolConfig,
    SAMLApplicationConfigurationInterface
} from "../../../../../features/applications";
import {
    AppState
} from "../../../../../features/core";
import { useDispatch, useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { store } from "../../../../../features/core";
import { addAlert } from "@wso2is/core/dist/src/store";
import { AlertLevels, TestableComponentInterface } from "@wso2is/core/dist/src/models";
import { ReactComponent as TomcatIcon } from "../../../../assets/images/icons/tomcat-icon.svg";
import { VerticalStepper } from "../vertical-stepper";
import { ApplicationConstants, SampleAppsEnum } from "../application-constants";

interface TryoutWebSAMLComponentProps extends TestableComponentInterface {
    application: ApplicationInterface;
}

/**
 * Tryout Component for Web SAML Template.
 */
export const TryoutWebSAMLComponent: FunctionComponent<TryoutWebSAMLComponentProps> = (
    props: TryoutWebSAMLComponentProps
): ReactElement => {

    const {
        application,
        [ "data-testid" ]: testId
    } = props;

    const dispatch = useDispatch();
    const { t } = useTranslation();

    const deploymentConfigs = store.getState().config.deployment;
    const [ inboundProtocolConfigs, setInboundProtocolConfigs ] = useState(undefined);
    const [ authConfig, setAuthConfig ] = useState(undefined);
    const [ integrateCode, setIntegrateCode ] = useState("");
    const [ selectedWebAppTechnology, setSelectedWebAppTechnology ] = useState("");
    const [ callBackURLNotSet, setCallbackURLNotSet ] = useState<boolean>(true);
    const helpPanelVisibilityGlobalState: boolean = useSelector((state: AppState) => state.helpPanel.visibility);
    const samlConfigurations: SAMLApplicationConfigurationInterface = useSelector(
        (state: AppState) => state.application.samlConfigurations);

    useEffect(() => {
        if ( application === undefined ) {
            return;
        }

        let protocolConfigs: any = {};
        const selectedProtocolList: string[] = [];

        application?.inboundProtocols?.map((protocol) => {

            const protocolName = mapProtocolTypeToName(protocol.type);

            getInboundProtocolConfig(application.id, protocolName)
                .then((response) => {
                    protocolConfigs = {
                        ...protocolConfigs,
                        [protocolName]: response
                    };

                    selectedProtocolList.push(protocolName);
                })
                .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.getInboundProtocolConfig" +
                                ".error.message")
                        }));

                        return;
                    }

                    dispatch(addAlert({
                        description: t("console:develop.features.applications.notifications.getInboundProtocolConfig" +
                            ".genericError.description"),
                        level: AlertLevels.ERROR,
                        message: t("console:develop.features.applications.notifications.getInboundProtocolConfig" +
                            ".genericError.message")
                    }));
                })
                .finally(() => {
                    setInboundProtocolConfigs(protocolConfigs);
                });
        });
    },  [ application ]);

    useEffect(() => {
        if (inboundProtocolConfigs == undefined) {
            return;
        }

        const configs = {
            clientHost: deploymentConfigs.clientHost,
            defaultAssertionConsumerUrl: inboundProtocolConfigs.saml.defaultAssertionConsumerUrl,
            issuer: inboundProtocolConfigs.saml.issuer,
            serverOrigin: deploymentConfigs.serverOrigin,
            tenant: deploymentConfigs.tenant,
            tenantPath: deploymentConfigs.tenantPath
        };
        setAuthConfig(configs);
        setIntegrateCode(
`SAML2_SP_ENTITY_ID=${inboundProtocolConfigs.saml.issuer}
IDP_PUBLIC_CERT=${samlConfigurations.certificate.replace(/\n/g, "\\\n")}
SAML2_IDP_URL=${samlConfigurations.ssoUrl}
SAML2_IDP_ENTITY_ID=${samlConfigurations.issuer}
SAML2_ENABLE_ASSERTION_SIGNING=false`
);
    }, [ inboundProtocolConfigs ]);

    const mapProtocolTypeToName = ((type: string): string => {
        let protocolName = type;
        if (protocolName === "oauth2") {
            protocolName = SupportedAuthProtocolTypes.OIDC;
        } else if (protocolName === "passivests") {
            protocolName = SupportedAuthProtocolTypes.WS_FEDERATION;
        } else if (protocolName === "wstrust") {
            protocolName = SupportedAuthProtocolTypes.WS_TRUST;
        } else if (protocolName === "samlsso") {
            protocolName = SupportedAuthProtocolTypes.SAML;
        }

        return protocolName;
    });

    const downloadEnvFile = (): void => {
        const blob = new Blob(
            [integrateCode],
            { type: "test/plain" }
        );
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.style.display = "none";
        a.href = url;
        a.download = ApplicationConstants.DOCKER_ENV_FILE_NAME;
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
    };

    const webAppContent = [ {
        stepTitle: `Select the technology ${selectedWebAppTechnology
            ? "(" + selectedWebAppTechnology + ")"
            : ""}`,
        stepContent: (
            <>
                <p>Select the technology of the sample below to proceed.</p>
                <Card.Group itemsPerRow={ helpPanelVisibilityGlobalState ? 5 : 9 }>
                    <Card
                        raised={ false }
                        data-testid={ `${ testId }-technology-tomcat-saml-agent` }
                        className={ `basic-card tech-selection ${ selectedWebAppTechnology === SampleAppsEnum.TOMCAT_SAML_AGENT
                            ? "selected"
                            : "" } ` }
                        onClick={ ()=> {
                            setSelectedWebAppTechnology(SampleAppsEnum.TOMCAT_SAML_AGENT)
                        } }
                    >
                        <Card.Content textAlign={ "center" }>
                            <TomcatIcon />
                            <Card.Description>
                                { SampleAppsEnum.TOMCAT_SAML_AGENT }
                            </Card.Description>
                        </Card.Content>
                    </Card>
                </Card.Group>
            </>
        )
    }, {
        stepTitle: "Configure the sample",
        stepContent: (
            <>
                <p>Download the <strong>{ ApplicationConstants.DOCKER_ENV_FILE_NAME }</strong> file to a preferred location.</p>
                { /* TODO : URL to be checked using a parameter */ }
                { callBackURLNotSet &&
                <Message warning>
                    <p>
                        In order to try out the sample, you need to append
                        <strong> 127.0.0.1 localhost.com</strong> to <strong>/etc/hosts </strong>
                        file of your machine to configure the hostname.
                    </p>
                </Message>
                }
                <Button
                    onClick={ downloadEnvFile }
                    className="download-config"
                    size='small'
                    primary
                    data-testid={ `${ testId }-download-config` }
                >
                    Download { ApplicationConstants.DOCKER_ENV_FILE_NAME }
                </Button>
                <Divider hidden/>
                <p>or create a file named <strong>{ ApplicationConstants.DOCKER_ENV_FILE_NAME }</strong> with the configuration below.</p>
                <div className="code-segment">
                    <div className="action-buttons">
                        <Button basic size='tiny' className="copy-config" icon>
                            <Icon name='copy' />
                        </Button>
                    </div>
                    <CodeEditor
                        showLineNumbers={ false }
                        language="htmlmixed"
                        sourceCode={ integrateCode }
                        beautify={ true }
                        theme={ "light" }
                        readOnly={ true }
                    />
                </div>
            </>
        )
    }, {
        stepTitle: "Run the sample",
        stepContent: (
            <>
                    { selectedWebAppTechnology === SampleAppsEnum.TOMCAT_SAML_AGENT &&
                    <>
                        <p>Run the below command in the location where you downloaded/created the
                            <strong>sample-app.env</strong> file from the previous step and visit:
                            <a>http://localhost.com:8080/sample-app</a>.</p>
                        <code>
                            docker container run --rm -p 8080:8080
                            --env-file $(PWD)/sample-app.env
                            asgardio/tomcat-saml-agent-sample
                        </code>
                    </>
                    }
            </>
        )
    } ];

    return (
        <VerticalStepper
            stepContent={ webAppContent }
            isNextEnabled={ selectedWebAppTechnology !== "" }
            isSidePanelOpen
        />
    );
};
