/**
 * Copyright (c) 2022, 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 { AccessControlConstants, Show } from "@wso2is/access-control";
import { hasRequiredScopes } from "@wso2is/core/helpers";
import { AlertLevels, IdentifiableComponentInterface } from "@wso2is/core/models";
import { MultiValueAttributeInterface } from "@wso2is/core/src/models";
import { addAlert } from "@wso2is/core/store";
import {
    CopyInputField,
    DocumentationLink,
    GridLayout,
    ListLayout,
    PageLayout,
    PrimaryButton,
    ResourceTab,
    Text,
    useDocumentation
} from "@wso2is/react-components";
import cloneDeep from "lodash-es/cloneDeep";
import React, { FunctionComponent, ReactElement, SyntheticEvent, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { RouteComponentProps } from "react-router";
import { 
    Button,
    Dropdown,
    DropdownItemProps,
    DropdownProps,
    Grid,
    Icon,
    PaginationProps, 
    Message as SemanticMessage,
    TabProps
} from "semantic-ui-react";
import {
    AdvancedSearchWithBasicFilters,
    AppState,
    EventPublisher,
    FeatureConfigInterface,
    UIConstants,
    UserBasicInterface,
    history,
    store
} from "../../../../features/core";
import { useServerConfigs } from "../../../../features/server-configurations";
import { useUsersList } from "../../../../features/users/api";
import { UserListInterface } from "../../../../features/users/models";
import { UserManagementUtils } from "../../../../features/users/utils";
import { SCIMConfigs } from "../../../configs/scim";
import { getUserStores, useInvitedUsersList } from "../api";
import { useOrganizationConfig } from "../api/organization";
import { GuestUsersList, OnboardedGuestUsersList } from "../components";
import {
    ADVANCED_USER_MGT,
    AdminAccountTypes,
    CONSUMER_USERSTORE,
    PRIMARY_USERSTORE,
    UserAccountTypes,
    UsersConstants
} from "../constants";
import { InvitationStatus, UserInviteInterface } from "../models";
import { AddUserWizard } from "../wizard";

/**
 * Props for the Users page.
 */
type CollaboratorsPageInterface = IdentifiableComponentInterface & RouteComponentProps;

/**
 * Temporary value to append to the list limit to figure out if the next button is there.
 * @typeParam TEMP_RESOURCE_LIST_ITEM_LIMIT_OFFSET - Temporary resource limit offset.
 */
const TEMP_RESOURCE_LIST_ITEM_LIMIT_OFFSET: number = 1;

/**
 * Users listing page.
 *
 * @param props - Props injected to the component.
 * @returns Administrator page react component.
 */
const CollaboratorsPage: FunctionComponent<CollaboratorsPageInterface> = (
    props: CollaboratorsPageInterface
): ReactElement => {

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

    const urlSearchParams: URLSearchParams = new URLSearchParams(location.search);

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

    const featureConfig: FeatureConfigInterface = useSelector((state: AppState) => state.config.ui.features);
    const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes);
    const tenantedConsoleUrl: string = useSelector((state: AppState) => state?.config?.deployment?.clientHost);
    const authenticatedUser: string = useSelector((state: AppState) => state?.auth?.username);
    const currentOrganization: string =  useSelector((state: AppState) => state?.config?.deployment?.tenant);

    const [ isGuestUsersNextPageAvailable, setIsGuestUsersNextPageAvailable ] = useState<boolean>(undefined);
    const [ searchQuery, setSearchQuery ] = useState<string>("");
    const [ listOffset, setListOffset ] = useState<number>(1);
    const [ listItemLimit, setListItemLimit ] = useState<number>(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
    const [ triggerClearQuery, setTriggerClearQuery ] = useState<boolean>(false);

    const [ showExtenalAdminWizard, setShowExtenalAdminWizard ] = useState<boolean>(false);
    const [ rolesList ] = useState([]);

    const [ invitationStatusOption, setInvitationStatusOption ] = useState<string>(InvitationStatus.ACCEPTED);
    const [ isInvitationStatusOptionChanged, setIsInvitationStatusOptionChanged ] = useState<boolean>(false);

    const [ paginatedGuestList, setPaginateGuestList ] = useState<UserInviteInterface[]>([]);
    const [ finalGuestList, setFinalGuestList ] = useState<UserInviteInterface[]>([]);
    const [ filterGuestList, setFilterGuestList ] = useState<UserInviteInterface[]>([]);
    const [ readOnlyUserStoresList , setReadOnlyUserStoresList ] = useState<string[]>([]);
    const [ isNextPageAvailable, setIsNextPageAvailable ] = useState<boolean>(false);
    const [ isAdvancedUserManagementDisabled, setAdvancedUserManagementDisabled ] = useState<boolean>(true);
    const [ selectedAddAdminType, setSelectedAddAdminType ] = useState<AdminAccountTypes>(AdminAccountTypes.INTERNAL);
    const [ selectedUserStore, setSelectedUserStore ] = useState<string>(CONSUMER_USERSTORE);
    const [ isLoadingForTheFirstTime, setIsLoadingForTheFirstTime ] = useState<boolean>(true);
    const [ isEnterpriseLoginEnabled, setIsEnterpriseLoginEnabled ] = useState<boolean>(false);
    const [ isUserStoreListLoading, setUserStoreListLoading ] = useState<boolean>(false);
    const [ isUserStoreDropdownDisabled, setUserStoreDropdownDisabled ] = useState<boolean>(false);
    const [ isSelectedUserStoreReadOnly, setSelectedUserStoreReadOnly ] = useState<boolean>(false);
    const [ userStoreError, setUserStoreError ] = useState(false);
    const [ activeTabIndex, setActiveTabIndex ] = useState<number>(0);
    const [ userStoreList, setUserStoreList ] = useState<DropdownItemProps[]>([]); 
    const organizationName = store.getState().auth.tenantDomain;

    const eventPublisher: EventPublisher = EventPublisher.getInstance();

    const modifiedLimit: number = listItemLimit + TEMP_RESOURCE_LIST_ITEM_LIMIT_OFFSET;
    // Excluding groups and roles from getUserList API call to improve performance.
    const excludedAttributes: string = UsersConstants.GROUPS_ATTRIBUTE;
    const {
        data: OrganizationConfig,
        isLoading: isOrgConfigRequestLoading,
        isValidating: isOrgConfigRequestRevalidating,
        error: orgConfigFetchRequestError
    } = useOrganizationConfig(
        organizationName,
        {
            revalidateIfStale: true
        }
    );

    const {
        data: originalAdminUserList,
        isLoading: isAdminUserListFetchRequestLoading,
        error: adminUserListFetchRequestError,
        mutate: mutateAdminUserListFetchRequest
    } = useUsersList(
        modifiedLimit,
        listOffset,
        (
            searchQuery === ""
                ? null
                : searchQuery
        ),
        null,
        activeTabIndex === 0 ? PRIMARY_USERSTORE : selectedUserStore,
        excludedAttributes,
        invitationStatusOption === InvitationStatus.ACCEPTED
    );

    const {
        data: guestUserList,
        isLoading: isGuestUserListFetchRequestLoading,
        error: guestUserListFetchRequestError,
        mutate: mutateGuestUserListFetchRequest
    } = useInvitedUsersList();

    const {
        data: serverConfigs,
        error: serverConfigsFetchRequestError
    } = useServerConfigs();

    useEffect(() => {
        setIsEnterpriseLoginEnabled(OrganizationConfig?.isEnterpriseLoginEnabled);
    }, [ isOrgConfigRequestLoading, isOrgConfigRequestRevalidating ]);

    /**
     * Sets the initial spinner.
     * TODO: Remove this once the loaders are finalized.
     */
    useEffect(() => {

        if (!originalAdminUserList && !guestUserList) {
            setIsLoadingForTheFirstTime(true);

            return;
        }

        setIsLoadingForTheFirstTime(false);
    }, [ originalAdminUserList, guestUserList ]);

    /**
     * Dispatches error notifications if Admin user fetch request fails.
     */
    useEffect(() => {
        if (!adminUserListFetchRequestError) {
            return;
        }

        if (adminUserListFetchRequestError?.response?.data?.description) {
            dispatch(addAlert({
                description: adminUserListFetchRequestError?.response?.data?.description
                    ?? adminUserListFetchRequestError?.response?.data?.detail
                        ?? t("console:manage.features.users.notifications.fetchUsers.error.description"),
                level: AlertLevels.ERROR,
                message: adminUserListFetchRequestError?.response?.data?.message
                    ?? t("console:manage.features.users.notifications.fetchUsers.error.message")
            }));

            return;
        }

        dispatch(addAlert({
            description: t("console:manage.features.users.notifications.fetchUsers.genericError." +
                "description"),
            level: AlertLevels.ERROR,
            message: t("console:manage.features.users.notifications.fetchUsers.genericError.message")
        }));
    }, [ adminUserListFetchRequestError ]);

    /**
     * Dispatches error notifications if Guest user fetch request fails.
     */
    useEffect(() => {
        if (!guestUserListFetchRequestError) {
            return;
        }

        if (guestUserListFetchRequestError?.response?.data?.description) {
            dispatch(addAlert({
                description: guestUserListFetchRequestError?.response?.data?.description
                    ?? guestUserListFetchRequestError?.response?.data?.detail
                        ?? t("console:manage.features.users.notifications.fetchUsers.error.description"),
                level: AlertLevels.ERROR,
                message: guestUserListFetchRequestError?.response?.data?.message
                    ?? t("console:manage.features.users.notifications.fetchUsers.error.message")
            }));

            return;
        }

        dispatch(addAlert({
            description: t("console:manage.features.users.notifications.fetchUsers.genericError. " +
                "description"),
            level: AlertLevels.ERROR,
            message: t("console:manage.features.users.notifications.fetchUsers.genericError.message")
        }));
    }, [ guestUserListFetchRequestError ]);

    /**
     * Dispatches error notifications if server configs fetch request fails.
     */
    useEffect(() => {
        if (!serverConfigsFetchRequestError) {
            return;
        }

        if (serverConfigsFetchRequestError?.response?.data?.description) {
            dispatch(addAlert({
                description: serverConfigsFetchRequestError?.response?.data?.description
                    ?? serverConfigsFetchRequestError?.response?.data?.detail
                        ?? t("console:manage.features.users.notifications.fetchUsers.error.description"),
                level: AlertLevels.ERROR,
                message: serverConfigsFetchRequestError?.response?.data?.message
                    ?? t("console:manage.features.users.notifications.fetchUsers.error.message")
            }));

            return;
        }

        dispatch(addAlert({
            description: t("console:manage.features.users.notifications.fetchUsers.genericError. " +
                "description"),
            level: AlertLevels.ERROR,
            message: t("console:manage.features.users.notifications.fetchUsers.genericError.message")
        }));
    }, [ serverConfigsFetchRequestError ]);

    /**
     * Dispatches error notifications if Organization config fetch request fails.
     */
    useEffect(() => {
        if (!orgConfigFetchRequestError) {
            return;
        }
        
        if (orgConfigFetchRequestError?.response?.data?.description) {
            dispatch(addAlert({
                description: orgConfigFetchRequestError?.response?.data?.description
                    ?? orgConfigFetchRequestError?.response?.data?.detail
                        ?? t("extensions:manage.users.administratorSettings.error.description"),
                level: AlertLevels.ERROR,
                message: orgConfigFetchRequestError?.response?.data?.message
                    ?? t("extensions:manage.users.administratorSettings.error.message")
            }));
        
            return;
        }
        
        dispatch(addAlert({
            description: t("extensions:manage.users.administratorSettings.genericError." +
                        "description"),
            level: AlertLevels.ERROR,
            message: t("extensions:manage.users.administratorSettings.genericError.message")
        }));
    }, [ orgConfigFetchRequestError ]);

    /**
     * Handles the search query changes.
     */
    useEffect(() => {
        if (invitationStatusOption === InvitationStatus.ACCEPTED) {
            return;
        }

        setListOffset(0);
        if (searchQuery === "email co " || searchQuery === "" || searchQuery === null) {
            setPaginateGuestList(guestUserList);
            setFilterGuestList([]);

            return;
        } else if (searchQuery) {
            let searchList: UserInviteInterface[] = guestUserList;

            if (filterGuestList.length > 0) {
                searchList = filterGuestList;
            }
            if (searchQuery.includes("email sw ")) {
                const searchValue = searchQuery.split("sw ")[1];

                searchList = searchList.filter((invite) => {
                    return invite.email.startsWith(searchValue);
                });
            } else if (searchQuery.includes("email ew ")) {
                const searchValue = searchQuery.split("ew ")[1];

                searchList = searchList.filter((invite) => {
                    return invite.email.endsWith(searchValue);
                });
            } else if (searchQuery.includes("email eq ")) {
                const searchValue = searchQuery.split("eq ")[1];

                searchList = searchList.filter((invite) => {
                    return (invite.email === searchValue);
                });
            } else if (searchQuery.includes("email co ")) {
                const searchValue = searchQuery.split("co ")[1];

                searchList = searchList.filter((invite) => {
                    return invite.email.includes(searchValue);
                });
            }
            setPaginateGuestList(searchList);
            setFilterGuestList(searchList);
        }
    }, [ searchQuery ]);

    /**
     * User effect to handle Pagination for pending/expired Guest.
     */
    useEffect(() => {
        if (invitationStatusOption === InvitationStatus.ACCEPTED) {
            return;
        }

        let finalInvitations: UserInviteInterface[] = paginatedGuestList?.filter(
            (invitation) => invitation.status === invitationStatusOption.toUpperCase());

        if (finalInvitations.length > listItemLimit) {
            finalInvitations = finalInvitations.slice(listOffset, listOffset + listItemLimit);
            setFinalGuestList(finalInvitations);
            setIsNextPageAvailable(finalInvitations.length === listItemLimit);
        } else {
            setFinalGuestList(finalInvitations);
            setIsNextPageAvailable(false);
        }
    }, [ paginatedGuestList, listOffset, listItemLimit, isInvitationStatusOptionChanged ]);

    /**
     * Handles guest user pagination.
     */
    useEffect(() => {
        setPaginateGuestList(guestUserList);
    }, [ guestUserList ]);

    /**
     * Set default value for offset & item limit.
     */
    useEffect(() => {
        if (!isInvitationStatusOptionChanged) {
            return;
        }
        setListOffset(0);
        setListItemLimit(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
        handleSearchQueryClear();
        setIsInvitationStatusOptionChanged(false);
    }, [ isInvitationStatusOptionChanged ]);

    /**
     * Handles the invitation status option changes.
     */
    useEffect(() => {
        checkAdvancedUserManagementStatus();
        getUserStoreList();
        
        // Default value of invitationStatusOption is ACCEPTED. This webhook logic needs to be ignored if the
        // invitationStatusOption has been manually set externally.
        if (InvitationStatus.ACCEPTED.toUpperCase() === invitationStatusOption.toUpperCase()) {
            if (!adminUserList || adminUserList.totalResults == 0) {
                if (guestUserList?.filter((invitation) =>
                    invitation.status === InvitationStatus.PENDING.toUpperCase()).length > 0) {
                    setInvitationStatusOption(InvitationStatus.PENDING);
                    setIsInvitationStatusOptionChanged(true);
                } else if (guestUserList?.filter((invitation) =>
                    invitation.status === InvitationStatus.EXPIRED.toUpperCase()).length > 0) {
                    setInvitationStatusOption(InvitationStatus.EXPIRED);
                    setIsInvitationStatusOptionChanged(true);
                }
            }
        }
        // Reset invitationStatusOption to default value when unmounting this component.

        return () => {
            setInvitationStatusOption(InvitationStatus.ACCEPTED);
            setIsInvitationStatusOptionChanged(true);
        };
    }, []);

    /**
     * Subscribe to the URS search params to check for User create wizard triggers.
     * @example
     * If the URL contains a search param `?open=Customer`, it'll open up the user create wizard.
     */
    useEffect(() => {

        if (!urlSearchParams.get(UsersConstants.USER_CREATE_WIZARD_TRIGGER_URL_SEARCH_PARAM_KEY)) {
            return;
        }

        eventPublisher.publish("manage-users-click-create-new", {
            type: "collaborator"
        });
        setShowExtenalAdminWizard(true);
    }, [ urlSearchParams.get(UsersConstants.USER_CREATE_WIZARD_TRIGGER_URL_SEARCH_PARAM_KEY) ]);

    /**
     * Transform the original users list response from the API.
     *
     * @param usersList - User list from the API.
     * @returns Processed list of users.
     */
    const transformUserList = (usersList: UserListInterface): UserListInterface => {
        if (!usersList) {
            return;
        }

        const clonedUserList: UserListInterface = cloneDeep(usersList);
        const processedUserList: UserBasicInterface[]  = [];

        /**
         * Checks whether administrator role is present in the user.
         */
        const isAdminUser = (user: UserBasicInterface): boolean => {
            return user.roles.some((role) => role.display === UserAccountTypes.ADMINISTRATOR);
        };

        const isOwner = (user: UserBasicInterface):boolean => {
            return (user[ SCIMConfigs.scim.enterpriseSchema ]?.userAccountType === UserAccountTypes.OWNER);
        };

        clonedUserList.Resources = clonedUserList?.Resources?.map((resource: UserBasicInterface) => {
            // Filter out users belong to groups named "Administrator"
            if (!isAdminUser(resource)) {
                return null;
            }

            if (isOwner(resource) && UserManagementUtils.isAuthenticatedUser(authenticatedUser, resource?.userName)) {
                processedUserList[0] = resource;
                
                return null;
            } else {
                if ( UserManagementUtils.isAuthenticatedUser(authenticatedUser, resource?.userName)) {
                    processedUserList[0] = resource;

                    return null;
                }
                if (isOwner(resource)) {
                    processedUserList[1] = resource;

                    return null;
                }
            }

            let email: string | null = null;

            if (resource?.emails instanceof Array) {
                const emailElement: string | MultiValueAttributeInterface = resource?.emails[0];

                if (typeof emailElement === "string") {
                    email = emailElement;
                } else {
                    email = emailElement?.value;
                }
            }

            resource.emails = [ email ];

            return resource;
        });

        /**
         * Returns a moderated users list.
         *
         * @remarks There is no proper way to count the total entries in the userstore with LDAP.
         *  So as a workaround, when
         * fetching users, we request an extra entry to figure out if there is a next page.
         * TODO: Remove this function and other related variables once there is a proper fix for LDAP pagination.
         * @see {@link https://github.com/wso2/product-is/issues/7320}
         *
         * @param list - Users list retrieved from the API.
         * @param requestedLimit - Requested item limit.
         * @param popCount - Tempt count used which will be removed after figuring out if
         *  next page is available.
         * @returns moderated users list with proper pagination.
         */
        const moderateUsersList = (list: UserListInterface, requestedLimit: number,
            popCount: number = 1): UserListInterface => {

            const moderated: UserListInterface = list;

            if (moderated.Resources?.length === requestedLimit) {
                moderated.Resources?.splice(-1, popCount);
                setIsGuestUsersNextPageAvailable(true);
            } else {
                setIsGuestUsersNextPageAvailable(false);
            }

            return moderated;
        };

        clonedUserList.Resources = processedUserList.concat(clonedUserList.Resources)
            .filter(user => user !== undefined);

        return moderateUsersList(clonedUserList, modifiedLimit, TEMP_RESOURCE_LIST_ITEM_LIMIT_OFFSET);
    };

    const getUserStoreList = (): void => {
        setUserStoreListLoading(true);

        getUserStores()
            .then((response) => {      
                const readOnlyUserStoreArray = [];                          
                const userStoreArray = response?.map((item, index) => {
                    // Set readOnly userstores based on the type.
                    if (item.typeName === UsersConstants.READONLY_USERSTORE_TYPE_NAME) {
                        readOnlyUserStoreArray.push(item.name.toUpperCase());
                    }
                    
                    return {
                        key: index,
                        text: item.name.toUpperCase(),
                        value: item.name.toUpperCase()
                    };
                });

                setUserStoreError(false);
                setUserStoreList(userStoreArray);
                setReadOnlyUserStoresList(readOnlyUserStoreArray);
                setUserStoreDropdownDisabled(userStoreArray.length <= 1);
            }).catch((error) => {
                if (error?.response?.data?.description) {
                    dispatch(addAlert({
                        description: error?.response?.data?.description ?? error?.response?.data?.detail
                            ?? t("console:manage.features.users.notifications.fetchUserStores.error.description"),
                        level: AlertLevels.ERROR,
                        message: error?.response?.data?.message
                            ?? t("console:manage.features.users.notifications.fetchUserStores.error.message")
                    }));

                    return;
                }

                dispatch(addAlert({
                    description: t("console:manage.features.users.notifications.fetchUserStores.genericError." +
                        "description"),
                    level: AlertLevels.ERROR,
                    message: t("console:manage.features.users.notifications.fetchUserStores.genericError.message")
                }));

                setUserStoreError(true);

                return;
            })
            .finally(() => {
                setUserStoreListLoading(false);
            });
    };

    const handleUserStoreChange = (event, data: DropdownProps): void => {        
        setSelectedUserStore(data.value as string);
        setSelectedUserStoreReadOnly(readOnlyUserStoresList?.includes(data.value.toString().toUpperCase()));
        setInvitationStatusOption(InvitationStatus.ACCEPTED);
        setIsInvitationStatusOptionChanged(true);

        // Reset pagination values
        setListOffset(0);
        setListItemLimit(UIConstants.DEFAULT_RESOURCE_LIST_ITEM_LIMIT);
    };

    const adminUserList = useMemo(() => {
        return transformUserList(originalAdminUserList);
    }, [ originalAdminUserList ]);

    const handlePaginationChange = (event: React.MouseEvent<HTMLAnchorElement>, data: PaginationProps): void => {
        setListOffset((data.activePage as number - 1) * listItemLimit);
    };

    const handleItemsPerPageDropdownChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps)
        : void => {
        setListItemLimit(data.value as number);
    };

    const invitationStatusOptions = [
        {
            key: 1,
            text: "Accepted",
            value: "Accepted"
        },
        {
            key: 2,
            text: "Pending",
            value: "Pending"
        },
        {
            key: 3,
            text: "Expired",
            value: "Expired"
        }
    ];

    /**
     * Handles the `onSearchQueryClear` callback action.
     */
    const handleSearchQueryClear = (): void => {
        setTriggerClearQuery(!triggerClearQuery);
        setSearchQuery("");
    };

    /**
     * Handles the `onFilter` callback action from the
     * users search component.
     *
     * @param query - Search query for filtering users.
     */
    const handleUserFilter = (query: string): void => {
        setSearchQuery(query);

        if (invitationStatusOption === InvitationStatus.ACCEPTED) {
            if (query === "userName sw ") {
                setSearchQuery(null);

                return;
            }

            setSearchQuery(query);
        }
    };

    const handleAccountStatusChange = (event: React.MouseEvent<HTMLAnchorElement>, data: DropdownProps): void => {
        setInvitationStatusOption(data.value as string);
        setIsInvitationStatusOptionChanged(true);
    };

    /**
     * Set the disabled/enabled status for advanced user management features. 
     */
    const checkAdvancedUserManagementStatus = ():void => {
        const disabledUserFeatures = featureConfig.users.disabledFeatures;

        setAdvancedUserManagementDisabled(disabledUserFeatures?.includes(ADVANCED_USER_MGT));
    };
    
    /**
     * Show the message about the tenanted console URL.
     */
    const renderTenantedConsoleLink = () => {
        const generateContent = () => {
            return (
                <Grid verticalAlign="middle">
                    <Grid.Column floated="left" width={ 9 }>
                        <Text className="message-info-text">
                            <p>  { t("extensions:manage.users.collaboratorAccounts.consoleInfo") } </p>
                        </Text>
                    </Grid.Column>
                    <Grid.Column floated="right" width={ 6 }>
                        <CopyInputField
                            value={ tenantedConsoleUrl }
                            className="consumer-url-input"
                            data-componentid={ `${ componentId }-tenanted-console-link` }
                        />
                    </Grid.Column>
                </Grid>
            );
        };

        return (
            <div className="mt-0 mb-1">
                {
                    <SemanticMessage
                        style={ {
                            borderRadius: "4px",
                            boxShadow: "0 0 0 1px rgb(34 36 38 / 22%) inset, 0 0 0 0 transparent !important"
                        } }
                        content={ generateContent() }
                    />
                }
            </div>
        );
    };

    const addAdminDropdown = (
        <PrimaryButton
            data-componentid={ `${ componentId }-add-admin-button` }
            onClick={ () => {
                eventPublisher.publish("admins-click-add-new-button");
            } }
        >
            <Icon name="add"/>
            { t("extensions:manage.users.buttons.addCollaboratorBtn") }
            <Icon name="dropdown" className="ml-3 mr-0"/>
        </PrimaryButton>
    );

    const addUserOptions = [
        { 
            "data-componentid": "admins-add-external-admin", 
            key: 1, 
            text: "Invite admins to Asgardeo", 
            value: AdminAccountTypes.EXTERNAL
        },
        { 
            "data-componentid": "admins-add-internal-admin", 
            key: 2, 
            text: "Assign admins from users", 
            value: AdminAccountTypes.INTERNAL
        }
    ];

    if (hasRequiredScopes(featureConfig?.guestUser, featureConfig?.guestUser?.scopes?.create, allowedScopes)) {
        addUserOptions.push();
    }

    const handleDropdownItemChange = (value: string): void => {
        if (!isAdvancedUserManagementDisabled && value === AdminAccountTypes.INTERNAL) {
            eventPublisher.publish("admins-click-create-new", {
                type: "internal admin"
            });
            setSelectedAddAdminType(AdminAccountTypes.INTERNAL);
            setShowExtenalAdminWizard(true);
        } else if (value === AdminAccountTypes.EXTERNAL) {
            eventPublisher.publish("admins-click-create-new", {
                type: "external admin"
            });
            setSelectedAddAdminType(AdminAccountTypes.EXTERNAL);
            setShowExtenalAdminWizard(true);
        }
    };

    const handleSettingsButton = () => {
        history.push(UsersConstants.getPaths().get("COLLABORATOR_SETTINGS_EDIT_PATH"));
    };

    const handleTabChange = (e: SyntheticEvent, data: TabProps): void => {
        setInvitationStatusOption(InvitationStatus.ACCEPTED);
        setActiveTabIndex(data.activeIndex as number);
        mutateGuestUserListFetchRequest();    
    };

    const resolveAdminTabPanes = (): any[] => {
        const panes: any[] = [];

        panes.push({
            componentId: "external-admins",
            menuItem: {
                content: "Asgardeo"
            },
            render: renderExtenalAdminsList
        });

        panes.push({
            componentId: "internal-admins",
            menuItem: {
                content: currentOrganization + " organization"
            },
            render: renderInternalAdminsList
        });

        return panes;
    };

    const renderAdministratorList = (): ReactElement => {
        if (isEnterpriseLoginEnabled && !isAdvancedUserManagementDisabled) {
            return (
                <ResourceTab
                    activeIndex= { activeTabIndex }
                    data-testid= { `${componentId}-administrator-tabs` }
                    defaultActiveIndex={ 0 }
                    onTabChange={ handleTabChange }
                    panes= { resolveAdminTabPanes() }
                />
            );
        }

        return renderExtenalAdminsList();
    };

    const renderExtenalAdminsList = ():ReactElement => {
        return(
            <ListLayout
                // TODO add sorting functionality.
                className="mt-5"
                advancedSearch={ (
                    <AdvancedSearchWithBasicFilters
                        onFilter={ handleUserFilter }
                        filterAttributeOptions={ (invitationStatusOption === InvitationStatus.ACCEPTED) ? [
                            {
                                key: 0,
                                text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                    "filterAttributeOptions.username"),
                                value: "userName"
                            },
                            {
                                key: 1,
                                text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                    "filterAttributeOptions.email"),
                                value: "emails"
                            },
                            {
                                key: 2,
                                text: "First Name",
                                value: "name.givenName"
                            },
                            {
                                key: 3,
                                text: "Last Name",
                                value: "name.familyName"
                            }
                        ]:
                            [
                                {
                                    key: 0,
                                    text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                        "filterAttributeOptions.email"),
                                    value: "email"
                                }
                            ]
                        }
                        filterAttributePlaceholder={
                            t("console:manage.features.users.advancedSearch.form.inputs.filterAttribute. " +
                                "placeholder")
                        }
                        filterConditionsPlaceholder={
                            t("console:manage.features.users.advancedSearch.form.inputs.filterCondition" +
                                ".placeholder")
                        }
                        filterValuePlaceholder={
                            t("console:manage.features.users.advancedSearch.form.inputs.filterValue" +
                                ".placeholder")
                        }
                        placeholder={ t("console:manage.features.users.advancedSearch.placeholder") }
                        defaultSearchAttribute={ (invitationStatusOption === InvitationStatus.ACCEPTED)
                            ? "userName": "email" }
                        defaultSearchOperator="co"
                        triggerClearQuery={ triggerClearQuery }
                    />
                ) }
                currentListSize={
                    invitationStatusOption === InvitationStatus.ACCEPTED
                        ? adminUserList?.Resources?.length
                        : finalGuestList?.length
                }
                listItemLimit={ listItemLimit }
                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
                data-componentid={ `${ componentId }-list-layout` }
                onPageChange={ handlePaginationChange }
                showPagination={ true }
                showTopActionPanel={ true }
                showPaginationPageLimit={ !isSelectedUserStoreReadOnly }
                totalPages={ invitationStatusOption === InvitationStatus.ACCEPTED ?
                    Math.ceil(adminUserList?.totalResults / listItemLimit) :
                    Math.ceil(paginatedGuestList?.length / listItemLimit) }
                totalListSize={ invitationStatusOption === InvitationStatus.ACCEPTED ?
                    adminUserList?.totalResults : paginatedGuestList?.length }
                onSearchQueryClear={ handleSearchQueryClear }
                resetPagination={ isInvitationStatusOptionChanged }
                paginationOptions={ {
                    disableNextButton: invitationStatusOption === InvitationStatus.ACCEPTED
                        ? !isGuestUsersNextPageAvailable
                        : !isNextPageAvailable
                } }
                disableRightActionPanel={ true }
                leftActionPanel={ (
                    <Dropdown
                        data-componentid={ `${ componentId }-list-userstore-dropdown` }
                        selection
                        options={ invitationStatusOptions && invitationStatusOptions }
                        onChange={ handleAccountStatusChange }
                        text={ `Filter by: ${ invitationStatusOption }` }
                    />
                ) }
            >
                {
                    (invitationStatusOption === InvitationStatus.ACCEPTED) && (
                        <OnboardedGuestUsersList
                            advancedSearch={ (
                                <AdvancedSearchWithBasicFilters
                                    onFilter={ handleUserFilter }
                                    filterAttributeOptions={ [
                                        {
                                            key: 0,
                                            text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                                "filterAttributeOptions.username"),
                                            value: "userName"
                                        },
                                        {
                                            key: 1,
                                            text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                                "filterAttributeOptions.email"),
                                            value: "emails"
                                        }
                                    ] }
                                    filterAttributePlaceholder={
                                        t("console:manage.features.users.advancedSearch.form.inputs" +
                                            ".filterAttribute.placeholder")
                                    }
                                    filterConditionsPlaceholder={
                                        t("console:manage.features.users.advancedSearch.form.inputs" +
                                            ".filterCondition.placeholder")
                                    }
                                    filterValuePlaceholder={
                                        t("console:manage.features.users.advancedSearch.form.inputs.filterValue" +
                                            ".placeholder")
                                    }
                                    placeholder={ t("console:manage.features.users.advancedSearch.placeholder") }
                                    defaultSearchAttribute="userName"
                                    defaultSearchOperator="co"
                                    triggerClearQuery={ triggerClearQuery }
                                />
                            ) }
                            onboardedGuestUsersList={ adminUserList }
                            userMetaListContent={ null }
                            isLoading={ isAdminUserListFetchRequestLoading }
                            realmConfigs={ serverConfigs?.realmConfig }
                            onEmptyListPlaceholderActionClick={ () => setShowExtenalAdminWizard(true) }
                            onSearchQueryClear={ handleSearchQueryClear }
                            searchQuery={ searchQuery }
                            data-componentid={ `${ componentId }-list` }
                            readOnlyUserStores={ null }
                            featureConfig={ featureConfig }
                            onUserDelete={ () => {
                                mutateAdminUserListFetchRequest();
                            } }
                        />
                    )
                }
                {
                    (invitationStatusOption === InvitationStatus.PENDING) && (
                        <GuestUsersList
                            invitationStatusOption={ invitationStatusOption }
                            onEmptyListPlaceholderActionClick={ () => setShowExtenalAdminWizard(true) }
                            onboardedGuestUserList={ adminUserList }
                            onSearchQueryClear={ handleSearchQueryClear }
                            guestUsersList={ finalGuestList }
                            getGuestUsersList={ () => mutateGuestUserListFetchRequest() }
                            isGuestUsersRequestLoading={ isGuestUserListFetchRequestLoading }
                            searchQuery={ searchQuery }
                        />
                    )
                }
                {
                    (invitationStatusOption === InvitationStatus.EXPIRED) && (
                        <GuestUsersList
                            invitationStatusOption={ invitationStatusOption }
                            onEmptyListPlaceholderActionClick={ () => setShowExtenalAdminWizard(true) }
                            onboardedGuestUserList={ adminUserList }
                            onSearchQueryClear={ handleSearchQueryClear }
                            guestUsersList={ finalGuestList?.filter(
                                (invitation) => invitation.status === InvitationStatus.EXPIRED.toUpperCase()) }
                            getGuestUsersList={ () => mutateGuestUserListFetchRequest() }
                            isGuestUsersRequestLoading={ isGuestUserListFetchRequestLoading }
                            searchQuery={ searchQuery }
                        />
                    )
                }
            </ListLayout>
        );
    };

    const renderInternalAdminsList = (): ReactElement => {
        return (
            <ListLayout
                // TODO add sorting functionality.
                className="mt-5"
                advancedSearch={ (
                    <AdvancedSearchWithBasicFilters
                        onFilter={ handleUserFilter }
                        filterAttributeOptions={ !isSelectedUserStoreReadOnly ? [
                            {
                                key: 0,
                                text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                    "filterAttributeOptions.username"),
                                value: "userName"
                            },
                            {
                                key: 1,
                                text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                    "filterAttributeOptions.email"),
                                value: "emails"
                            },
                            {
                                key: 2,
                                text: "First Name",
                                value: "name.givenName"
                            },
                            {
                                key: 3,
                                text: "Last Name",
                                value: "name.familyName"
                            }
                        ]:
                            [
                                {
                                    key: 0,
                                    text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                        "filterAttributeOptions.email"),
                                    value: "email"
                                }
                            ]
                        }
                        filterAttributePlaceholder={
                            t("console:manage.features.users.advancedSearch.form.inputs.filterAttribute. " +
                                "placeholder")
                        }
                        filterConditionsPlaceholder={
                            t("console:manage.features.users.advancedSearch.form.inputs.filterCondition" +
                                ".placeholder")
                        }
                        filterValuePlaceholder={
                            t("console:manage.features.users.advancedSearch.form.inputs.filterValue" +
                                ".placeholder")
                        }
                        placeholder={ t("console:manage.features.users.advancedSearch.placeholder") }
                        defaultSearchAttribute={ !isSelectedUserStoreReadOnly ? "userName": "email" }
                        defaultSearchOperator="co"
                        triggerClearQuery={ triggerClearQuery }
                    />
                ) }
                currentListSize={ adminUserList?.Resources?.length }
                listItemLimit={ listItemLimit }
                onItemsPerPageDropdownChange={ handleItemsPerPageDropdownChange }
                data-componentid={ `${ componentId }-list-layout` }
                onPageChange={ handlePaginationChange }
                showPagination={ true }
                showTopActionPanel={ true }
                showPaginationPageLimit={ !isSelectedUserStoreReadOnly }
                totalPages={ Math.ceil(adminUserList?.totalResults / listItemLimit) }
                totalListSize={ adminUserList?.totalResults }
                onSearchQueryClear={ handleSearchQueryClear }
                resetPagination={ isInvitationStatusOptionChanged }
                paginationOptions={ { disableNextButton: !isGuestUsersNextPageAvailable } }
                leftActionPanel={
                    !isUserStoreDropdownDisabled
                        ? (
                            <Dropdown
                                data-componentid={ `${ componentId }-userstore-dropdown` }
                                selection
                                options={ userStoreList }
                                onChange={ handleUserStoreChange }
                                text={ selectedUserStore }
                                loading={ isUserStoreListLoading }
                                disabled={ userStoreError }
                            /> 
                        ) : null
                }
            >
                <OnboardedGuestUsersList
                    advancedSearch={ (
                        <AdvancedSearchWithBasicFilters
                            onFilter={ handleUserFilter }
                            filterAttributeOptions={ [
                                {
                                    key: 0,
                                    text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                        "filterAttributeOptions.username"),
                                    value: "userName"
                                },
                                {
                                    key: 1,
                                    text: t("console:manage.features.users.advancedSearch.form.dropdown." +
                                        "filterAttributeOptions.email"),
                                    value: "emails"
                                }
                            ] }
                            filterAttributePlaceholder={
                                t("console:manage.features.users.advancedSearch.form.inputs" +
                                    ".filterAttribute.placeholder")
                            }
                            filterConditionsPlaceholder={
                                t("console:manage.features.users.advancedSearch.form.inputs" +
                                    ".filterCondition.placeholder")
                            }
                            filterValuePlaceholder={
                                t("console:manage.features.users.advancedSearch.form.inputs.filterValue" +
                                    ".placeholder")
                            }
                            placeholder={ t("console:manage.features.users.advancedSearch.placeholder") }
                            defaultSearchAttribute="userName"
                            defaultSearchOperator="co"
                            triggerClearQuery={ triggerClearQuery }
                        />
                    ) }
                    onboardedGuestUsersList={ adminUserList }
                    userMetaListContent={ null }
                    isLoading={ isAdminUserListFetchRequestLoading }
                    realmConfigs={ serverConfigs?.realmConfig }
                    onEmptyListPlaceholderActionClick={ () => setShowExtenalAdminWizard(true) }
                    onSearchQueryClear={ handleSearchQueryClear }
                    searchQuery={ searchQuery }
                    data-componentid={ `${ componentId }-list` }
                    readOnlyUserStores={ null }
                    featureConfig={ featureConfig }
                    onUserDelete={ () => {
                        mutateAdminUserListFetchRequest();
                    } }
                />
            </ListLayout>
        );
    };

    return (
        <PageLayout
            pageTitle="Administrators"
            action={ 
                !isGuestUserListFetchRequestLoading
                && !isOrgConfigRequestRevalidating
                && !isOrgConfigRequestLoading
                && (
                    <Show when={ AccessControlConstants.USER_WRITE }>
                        { !isAdvancedUserManagementDisabled && 
                            (<Button
                                data-componentid={ `${ componentId }-admin-settings-button` }
                                icon="setting"
                                onClick={ handleSettingsButton }
                            >
                            </Button>)
                        }
                        { (isEnterpriseLoginEnabled && !isAdvancedUserManagementDisabled) ? (
                            <Dropdown
                                data-componentid={ `${ componentId }-add-admin-dropdown` }
                                direction="left"
                                floating
                                icon={ null }
                                trigger={ addAdminDropdown }
                            >
                                <Dropdown.Menu >
                                    { addUserOptions.map((option) => (
                                        <Dropdown.Item
                                            key={ option.value }
                                            onClick={ ()=> handleDropdownItemChange(option.value) }
                                            { ...option }
                                            disabled= { !isEnterpriseLoginEnabled }
                                        />
                                    )) }
                                </Dropdown.Menu>
                            </Dropdown>
                        ) : (
                            <PrimaryButton
                                data-componentid={ `${ componentId }-add-admin-button` }
                                onClick={ () => {
                                    eventPublisher.publish("admins-click-add-new-button");
                                    setSelectedAddAdminType(AdminAccountTypes.EXTERNAL);
                                    setShowExtenalAdminWizard(true);
                                } }
                            >
                                <Icon name="add"/>
                                { t("extensions:manage.users.buttons.addCollaboratorBtn") }
                            </PrimaryButton>
                        ) }
                    </Show>
                )
            }
            title={ t("extensions:manage.users.collaboratorsTitle") }
            description={ (
                <>
                    { t("extensions:manage.users.collaboratorsSubTitle") }
                    <DocumentationLink
                        link={ getLink("manage.users.collaboratorAccounts.learnMore") }
                    >
                        { t("extensions:common.learnMore") }
                    </DocumentationLink>
                </>
            ) }
            contentTopMargin={ false }
            data-componentid={ `${ componentId }-page-layout` }
        >
            <GridLayout
                isLoading={ isLoadingForTheFirstTime }
                showTopActionPanel={ false }
            >
                { renderTenantedConsoleLink() }
                { renderAdministratorList() }
            </GridLayout>
            {
                showExtenalAdminWizard && (
                    <AddUserWizard
                        data-componentid={ `${ componentId }-add-admin-wizard-modal` }
                        closeWizard={ () => {
                            setShowExtenalAdminWizard(false);
                        } }
                        updateList={ () => mutateGuestUserListFetchRequest() }
                        rolesList={ rolesList }
                        emailVerificationEnabled={ true }
                        onInvitationSendSuccessful={ () => {                            
                            mutateGuestUserListFetchRequest();
                            eventPublisher.publish("manage-users-finish-creating-collaborator-user");
                            if (selectedAddAdminType === AdminAccountTypes.EXTERNAL) {
                                setInvitationStatusOption(InvitationStatus.PENDING);
                                setActiveTabIndex(0);
                            }
                            if (selectedAddAdminType === AdminAccountTypes.INTERNAL) {
                                setInvitationStatusOption(InvitationStatus.ACCEPTED);
                                setActiveTabIndex(1);
                            }
                            setIsInvitationStatusOptionChanged(true);
                        } }
                        defaultUserTypeSelection={ UserAccountTypes.ADMINISTRATOR }
                        adminTypeSelection={ selectedAddAdminType }
                        onUserUpdate={ () => {
                            if (selectedAddAdminType === AdminAccountTypes.EXTERNAL) {
                                setActiveTabIndex(0);
                            }
                            if (selectedAddAdminType === AdminAccountTypes.INTERNAL) {
                                setInvitationStatusOption(InvitationStatus.ACCEPTED);
                                setActiveTabIndex(1);
                            }   
                            mutateAdminUserListFetchRequest();
                        } }
                    />
                )
            }
        </PageLayout>
    );
};

/**
 * Default props for the component.
 */
CollaboratorsPage.defaultProps = {
    "data-componentid": "asgardeo-administrators"
};

/**
 * A default export was added to support React.lazy.
 * TODO: Change this to a named export once react starts supporting named exports for code splitting.
 * @see {@link https://reactjs.org/docs/code-splitting.html#reactlazy}
 */
export default CollaboratorsPage;
