/**
 * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). All Rights Reserved.
 *
 * This software is the property of WSO2 LLC. 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 { IdentityAppsApiException } from "@wso2is/core/exceptions";
import { hasRequiredScopes } from "@wso2is/core/helpers";
import { AlertInterface, AlertLevels, IdentifiableComponentInterface } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import {
    ConfirmationModal,
    ContentLoader,
    EmphasizedSegment,
    Heading
} from "@wso2is/react-components";
import { getOIDCData } from "apps/console/src/features/applications/api";
import { OIDCDataInterface } from "apps/console/src/features/applications/models";
import { RequestErrorInterface } from "apps/console/src/features/core/hooks/use-request";
import { AxiosError } from "axios";
import React, {
    Fragment,
    FunctionComponent,
    ReactElement,
    useEffect,
    useState
} from "react";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { Dispatch } from "redux";
import { Divider, Grid } from "semantic-ui-react";
import { PolicySection, SubscribedAPIResources } from ".";
import { AppState, history } from "../../../../../features/core";
import { ExtendedFeatureConfigInterface } from "../../../../configs/models";
import { useAPIResources } from "../../../api-resources/api";
import { APIResourcesConstants } from "../../../api-resources/constants";
import { unsubscribeAPIResources, useSubscribedAPIResources } from "../../api";
import { APIAuthorizationConstants } from "../../constants";
import { AuthorizedAPIListItemInterface } from "../../models";

/**
 * Application roles component.
 * 
 * @param props - Props related to application roles component.
 */
export const APIAuthorization: FunctionComponent<IdentifiableComponentInterface> = (
    props: IdentifiableComponentInterface
): ReactElement => {

    const {
        ["data-componentid"]: componentId
    } = props;

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

    const [ isSubAPIResourcesSectionLoading, setSubAPIResourcesSectionLoading ] = useState<boolean>(false);
    const [ isShownError, setIsShownError ] = useState<boolean>(false);
    const [ oidcData, setOidcData ] = useState<OIDCDataInterface>(undefined);
    const [ isClientCreditionalsGrantEnabled, setIsClientCreditionalsGrantEnabled ] = useState<boolean>(false);
    const [ removeSubscribedAPIResource, setRemoveSubscribedAPIResource ] = 
        useState<AuthorizedAPIListItemInterface>(null);
    const [ isUnsubscribeAPIResourceLoading, setIsUnsubscribeAPIResourceLoading ] = useState<boolean>(false);
    const [ isAPIResourceUnsubscribed, setIsAPIResourceUnsubscribed ] = useState<boolean>(false);

    const featureConfig: ExtendedFeatureConfigInterface = useSelector((state: AppState) => state.config.ui.features);
    const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes);

    const path: string[] = history.location.pathname.split("/");
    const appId: string = path[path.length - 1].split("#")[0];

    const {
        data: allAPIResourcesListData,
        isLoading: isAllAPIResourcesListLoading,
        error: allAPIResourcesFetchRequestError,
        mutate: mutateAllAPIResourcesList
    } = useAPIResources();

    const {
        data: subscribedAPIResourcesListData,
        isLoading: isSubscribedAPIResourcesListLoading,
        error: subscribedAPIResourcesFetchRequestError,
        mutate: mutateSubscribedAPIResourcesList
    } = useSubscribedAPIResources(appId);

    /**
     * The following method is used to get OIDC data of the application.
     */
    const getOIDCDataOfTheApplication = (): void => {
        getOIDCData(appId)
            .then((response: OIDCDataInterface) => {
                setOidcData(response);
            })
            .catch(() => {
                setOidcData(undefined);
            });
    };

    /**
     * The following useEffect is used to get OIDC data of the application.
     */
    useEffect(() => {
        getOIDCDataOfTheApplication();
    }, []);

    /**
     * The following useEffect is used to check if the client credentials grant is enabled.
     */
    useEffect(() => {
        if (oidcData) {
            const grantTypes: string[] = oidcData.grantTypes;

            if (grantTypes.includes(APIAuthorizationConstants.CLIENT_CREDENTIALS_GRANT_TYPE)) {
                setIsClientCreditionalsGrantEnabled(true);
            } else {
                setIsClientCreditionalsGrantEnabled(false);
            }
        }
    }, [ oidcData ]);

    /**
     * The following useEffect is used to handle if any error occurs while fetching API resources
     */
    useEffect(() => {
        if (allAPIResourcesFetchRequestError || subscribedAPIResourcesFetchRequestError) {
            if (!isShownError) {
                setIsShownError(true);

                const error: AxiosError<RequestErrorInterface> = allAPIResourcesFetchRequestError ?
                    allAPIResourcesFetchRequestError : subscribedAPIResourcesFetchRequestError;

                switch (error.response?.data?.code) {
                    case APIResourcesConstants.UNAUTHORIZED_ACCESS:
                        dispatch(addAlert<AlertInterface>({
                            description: t("extensions:develop.apiResource.notifications.getAPIResources" +
                                ".unauthorizedError.description"),
                            level: AlertLevels.ERROR,
                            message: t("extensions:develop.apiResource.notifications.getAPIResources" +
                                ".unauthorizedError.message")
                        }));

                        break;

                    default:
                        dispatch(addAlert<AlertInterface>({
                            description: t("extensions:develop.apiResource.notifications.getAPIResources" +
                                ".genericError.description"),
                            level: AlertLevels.ERROR,
                            message: t("extensions:develop.apiResource.notifications.getAPIResources" +
                                ".genericError.message")
                        }));
                }
            }
        }
    }, [ allAPIResourcesFetchRequestError, subscribedAPIResourcesFetchRequestError ]);

    /**
     * The following useEffect is used to handle loading state of when API resources are being fetched.
     */
    useEffect(() => {
        setSubAPIResourcesSectionLoading(isAPIResourceUnsubscribed || 
            isAllAPIResourcesListLoading || isSubscribedAPIResourcesListLoading);
    }, [ isAPIResourceUnsubscribed, isAllAPIResourcesListLoading, isSubscribedAPIResourcesListLoading ]);

    /**
     * The following useEffect is used to update the API resources list once a mutate function is called.
     */
    useEffect(() => {
        if (isAPIResourceUnsubscribed) {
            mutateAllAPIResourcesList();
            mutateSubscribedAPIResourcesList();
            setIsAPIResourceUnsubscribed(false);
        }
    }, [ isAPIResourceUnsubscribed ]);

    /**
     * Handles the hide of the policy selection./
     */
    const isHidePolicySelection = (): boolean => {
        return ( subscribedAPIResourcesFetchRequestError !== null || allAPIResourcesFetchRequestError !== null
            || allAPIResourcesListData.apiResources.length === 0 || subscribedAPIResourcesListData.length === 0 );
    };

    /**
     * Handles unsubscribe API resource.
     *
     * @param apiResourceId - API resource ID.
     */
    const handleAPIResourceUnsubscribe = (): void => {

        setIsUnsubscribeAPIResourceLoading(true);
        unsubscribeAPIResources(appId, removeSubscribedAPIResource?.apiId)
            .then(() => {
                dispatch(addAlert<AlertInterface>({
                    description: t("extensions:develop.applications.edit.sections." +
                        "apiAuthorization.sections.apiSubscriptions.notifications.unSubscribe.success.description"),
                    level: AlertLevels.SUCCESS,
                    message: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                        ".apiSubscriptions.notifications.unSubscribe.success.message")
                }));

                setIsUnsubscribeAPIResourceLoading(false);
                setIsAPIResourceUnsubscribed(true);
            })
            .catch((error: IdentityAppsApiException) => {
                switch(error?.code) {
                    case APIResourcesConstants.UNAUTHORIZED_ACCESS:
                        dispatch(addAlert<AlertInterface>({
                            description: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.notifications.unSubscribe.unauthorizedError.description"),
                            level: AlertLevels.ERROR,
                            message: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.notifications.unSubscribe.unauthorizedError.message")
                        }));

                        break;
                        
                    case APIResourcesConstants.NO_VALID_API_RESOURCE_ID_FOUND:
                    case APIResourcesConstants.API_RESOURCE_NOT_FOUND:
                        dispatch(addAlert<AlertInterface>({
                            description: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.notifications.unSubscribe.notFoundError.description"),
                            level: AlertLevels.ERROR,
                            message: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.notifications.unSubscribe.notFoundError.message")
                        }));

                        break;

                    default:
                        dispatch(addAlert<AlertInterface>({
                            description: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.notifications.unSubscribe.genericError.description"),
                            level: AlertLevels.ERROR,
                            message: t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.notifications.unSubscribe.genericError.message")
                        }));
                }
            })
            .finally(() => {
                setIsUnsubscribeAPIResourceLoading(false);
                setRemoveSubscribedAPIResource(null);
            });
    };

    /**
     * Check scopes available for update API resources
     */
    const isScopesAvailableForUpdate = (): boolean => {
        return hasRequiredScopes(featureConfig?.applications,
            featureConfig?.applications?.scopes?.update, allowedScopes);
    };

    return (
        <Fragment>
            <EmphasizedSegment padded="very" data-componentid={ ` ${componentId}-sub-api-resources-section` }>
                <Grid>
                    <Grid.Row>
                        <Grid.Column className="heading-wrapper" computer={ 10 }>
                            <Heading as="h4">
                                { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                    ".apiSubscriptions.heading") }
                            </Heading>
                            <Heading subHeading ellipsis as="h6" >
                                { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                    ".apiSubscriptions.subHeading") }
                            </Heading>
                        </Grid.Column >
                    </Grid.Row>
                </Grid>
                <Divider hidden />
                <Grid>
                    <Grid.Row>
                        <Grid.Column>
                            {
                                isSubAPIResourcesSectionLoading
                                    ? <ContentLoader inline="centered" active />
                                    : (<SubscribedAPIResources
                                        allAPIResourcesListData={ allAPIResourcesListData?.apiResources }
                                        allAPIResourcesFetchRequestError={ allAPIResourcesFetchRequestError }
                                        subscribedAPIResourcesListData={ subscribedAPIResourcesListData }
                                        subscribedAPIResourcesFetchRequestError=
                                            { subscribedAPIResourcesFetchRequestError }
                                        isShownPlaceholder={ isHidePolicySelection() }
                                        setRemoveSubscribedAPIResource={ setRemoveSubscribedAPIResource }
                                        isScopesAvailableForUpdate={ isScopesAvailableForUpdate() }
                                    />)
                            }
                        </Grid.Column>
                    </Grid.Row>
                </Grid>
            </EmphasizedSegment>
            <EmphasizedSegment padded="very" data-componentid={ ` ${componentId}-policy-section` }>
                <Grid>
                    <Grid.Row>
                        <Grid.Column className="heading-wrapper" computer={ 10 }>
                            <Heading as="h4">
                                { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                    ".policySection.heading") }
                            </Heading>
                            <Heading subHeading ellipsis as="h6" >
                                { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                    ".policySection.subHeading") }
                            </Heading>
                        </Grid.Column >
                    </Grid.Row>
                </Grid>
                <Divider hidden />
                <Grid>
                    <Grid.Row>
                        <Grid.Column>
                            <PolicySection
                                isClientCredentialsEnabled={ isClientCreditionalsGrantEnabled }
                                isScopesAvailableForUpdate={ isScopesAvailableForUpdate() } />
                        </Grid.Column>
                    </Grid.Row>
                </Grid>
            </EmphasizedSegment>

            {
                removeSubscribedAPIResource && (
                    <ConfirmationModal
                        primaryActionLoading={ isUnsubscribeAPIResourceLoading }
                        open={ removeSubscribedAPIResource !== null }
                        onClose={ (): void => setRemoveSubscribedAPIResource(null) }
                        type="negative"
                        assertionHint={ t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                            ".apiSubscriptions.confirmations.unsubscribeAPIResource.assertionHint") }
                        assertionType="checkbox"
                        primaryAction={ t("common:confirm") }
                        secondaryAction={ t("common:cancel") }
                        onSecondaryActionClick={ (): void => setRemoveSubscribedAPIResource(null) }
                        onPrimaryActionClick={ (): void => handleAPIResourceUnsubscribe() }
                        data-componentid={ `${componentId}-delete-confirmation-modal` }
                        closeOnDimmerClick={ false }
                    >
                        <ConfirmationModal.Header
                            data-componentid={ `${componentId}-delete-confirmation-modal-header` }
                        >
                            { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.confirmations.unsubscribeAPIResource.header") }
                        </ConfirmationModal.Header>
                        <ConfirmationModal.Message
                            attached
                            negative
                            data-componentid={ `${componentId}-delete-confirmation-modal-message` }
                        >
                            { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.confirmations.unsubscribeAPIResource.message") }
                        </ConfirmationModal.Message>
                        <ConfirmationModal.Content
                            data-componentid={ `${componentId}-delete-confirmation-modal-content` }
                        >
                            { t("extensions:develop.applications.edit.sections.apiAuthorization.sections" +
                                ".apiSubscriptions.confirmations.unsubscribeAPIResource.content") }
                        </ConfirmationModal.Content>
                    </ConfirmationModal>
                )
            }
        </Fragment>

    );
};

/**
 * Default props for application roles tab component.
 */
APIAuthorization.defaultProps = {
    "data-componentid": "api-authorization-tab"
};
