import Add from '../../../../../node_modules/@mui/icons-material/esm/Add.mjs';
import CheckCircle from '../../../../../node_modules/@mui/icons-material/esm/CheckCircle.mjs';
import DeleteOutlined from '../../../../../node_modules/@mui/icons-material/esm/DeleteOutlined.mjs';
import EditOutlined from '../../../../../node_modules/@mui/icons-material/esm/EditOutlined.mjs';
import EmailOutlined from '../../../../../node_modules/@mui/icons-material/esm/EmailOutlined.mjs';
import VisibilityOutlined from '../../../../../node_modules/@mui/icons-material/esm/VisibilityOutlined.mjs';
import React__default, { useMemo, useCallback, useState } from 'react';
import index from '../../../../../node_modules/swr/infinite/dist/index.mjs';
import { extractErrorMessage } from '../../utils/extractErrorMessage.mjs';
import { useActionMenu } from '../components/ActionMenu.mjs';
import { Alert } from '../components/Alert.mjs';
import { Button } from '../components/Button.mjs';
import { FilterMenu } from '../components/FilterMenu.mjs';
import { FlexBox } from '../shared/components/FlexBox.mjs';
import { PaginatedTable } from '../components/PaginatedTable.mjs';
import { RolesList } from '../components/RolesList.mjs';
import { SearchBar } from '../components/SearchBar.mjs';
import { Typography } from '../components/Typography.mjs';
import { useToast } from '../shared/components/Toast.mjs';
import { decorateCurrentMemberName } from '../utils/decorateCurrentMemberName.mjs';
import { fetchMembers } from '../utils/fetchMembers.mjs';
import { useDebouncedState } from '../utils/useDebouncedState.mjs';
import { useItemsPerPage, itemsPerPageOptions } from '../utils/useItemsPerPage.mjs';
import { useOrgInfo } from '../utils/useOrgInfo.mjs';
import { usePagination } from '../utils/usePagination.mjs';
import { usePersistentFilter } from '../utils/usePersistentFilter.mjs';
import { useRbac } from '../utils/useRbac.mjs';
import { useRoleAutocomplete } from '../utils/useRoleAutocomplete.mjs';
import { useSelf } from '../utils/useSelf.mjs';
import { useStytchClient } from '../utils/useStytchClient.mjs';
import { getMemberStatusDisplayName } from './getMemberStatusDisplayName.mjs';
import { useInviteModal, InviteModal } from './InviteModal.mjs';
import { useMemberManagementRouterController } from './MemberManagementRouter.mjs';
import { allMemberStatusesSet, allMemberStatuses } from './MemberStatus.mjs';
import { useMemberActivation } from './useMemberActivation.mjs';
import { useSendInviteEmail } from './useSendInviteEmail.mjs';

const MIN_EMAIL_FUZZY_SEARCH_LENGTH = 3;
const MEMBER_LIST_TABLE_VIEW_ID = 'adminPortalMemberList';
const DEFAULT_STATUSES_FILTER = new Set([
    'active',
    'invited',
    'pending'
]);
const REINVITE_MEMBER_STATUS = new Set([
    'invited',
    'pending'
]);
const allStatusesFilterItems = allMemberStatuses.map((status)=>({
        label: getMemberStatusDisplayName(status),
        value: status
    }));
const useMembers = ({ limit, email: emailRaw, roles, statuses })=>{
    const client = useStytchClient();
    const orgInfo = useOrgInfo();
    const email = emailRaw && emailRaw.length >= MIN_EMAIL_FUZZY_SEARCH_LENGTH ? emailRaw : undefined;
    return index((index, prevData)=>{
        if (prevData && !prevData.results_metadata.next_cursor) {
            return null;
        }
        return {
            orgId: orgInfo.data?.organization_id,
            method: 'members.search',
            limit,
            email,
            // Stabilize the query key by sorting roles and statuses deterministically
            roles: roles?.slice().sort(),
            statuses: statuses?.slice().sort(),
            cursor: prevData?.results_metadata.next_cursor
        };
    }, fetchMembers(client), {
        revalidateFirstPage: false
    });
};
const getMemberId = (item)=>item.member_id;
const ColumnTitleWithFilter = ({ items, onChange, value, title })=>{
    const [container, setContainer] = useState(null);
    return /*#__PURE__*/ React__default.createElement("div", {
        ref: setContainer
    }, /*#__PURE__*/ React__default.createElement(FlexBox, {
        gap: 1,
        alignItems: "center"
    }, title, /*#__PURE__*/ React__default.createElement(FilterMenu, {
        anchorEl: container ?? undefined,
        items: items,
        value: value,
        onChange: onChange
    })));
};
const emptySet = new Set();
const MemberListScreen = ()=>{
    const { navigate } = useMemberManagementRouterController();
    const { data: canCreateMemberPerm } = useRbac('stytch.member', 'create');
    const { data: canUpdateMemberIsBreakglassPerm } = useRbac('stytch.member', 'update.settings.is-breakglass');
    const { data: canUpdateMemberRolesPerm } = useRbac('stytch.member', 'update.settings.roles');
    const { data: canUpdateMemberNamePerm } = useRbac('stytch.member', 'update.info.name');
    const { data: canUpdateMemberUntrustedMetadataPerm } = useRbac('stytch.member', 'update.info.untrusted-metadata');
    const { data: canUpdateMemberMfaPhonePerm } = useRbac('stytch.member', 'update.info.mfa-phone');
    const { data: canDeleteMemberMfaPhonePerm } = useRbac('stytch.member', 'update.info.delete.mfa-phone');
    const { data: canDeleteMemberMfaTotpPerm } = useRbac('stytch.member', 'update.info.delete.mfa-totp');
    const { data: canDeleteMemberPasswordPerm } = useRbac('stytch.member', 'update.info.delete.password');
    const { data: canUpdateMemberMfaEnrolledPerm } = useRbac('stytch.member', 'update.settings.mfa-enrolled');
    const { data: canUpdateMemberDefaultMfaMethodPerm } = useRbac('stytch.member', 'update.settings.default-mfa-method');
    const { data: canDeleteMemberPerm } = useRbac('stytch.member', 'delete');
    const { data: canRevokeMemberSessionsPerm } = useRbac('stytch.member', 'revoke-sessions');
    const { data: canUpdateSelfNamePerm } = useRbac('stytch.self', 'update.info.name');
    const { data: canUpdateSelfUntrustedMetadataPerm } = useRbac('stytch.self', 'update.info.untrusted-metadata');
    const { data: canUpdateSelfMfaPhonePerm } = useRbac('stytch.self', 'update.info.mfa-phone');
    const { data: canDeleteSelfMfaPhonePerm } = useRbac('stytch.self', 'update.info.delete.mfa-phone');
    const { data: canDeleteSelfMfaTotpPerm } = useRbac('stytch.self', 'update.info.delete.mfa-totp');
    const { data: canDeleteSelfPasswordPerm } = useRbac('stytch.self', 'update.info.delete.password');
    const { data: canUpdateSelfMfaEnrolledPerm } = useRbac('stytch.self', 'update.settings.mfa-enrolled');
    const { data: canUpdateSelfDefaultMfaMethodPerm } = useRbac('stytch.self', 'update.settings.default-mfa-method');
    const { data: canDeleteSelfPerm } = useRbac('stytch.self', 'delete');
    const { data: canRevokeSelfSessionsPerm } = useRbac('stytch.self', 'revoke-sessions');
    const { data: canGetOrgCustomRoles } = useRbac('stytch.custom-org-roles', 'get');
    const canUpdateMember = canDeleteMemberMfaPhonePerm || canDeleteMemberMfaTotpPerm || canDeleteMemberPasswordPerm || canUpdateMemberMfaPhonePerm || canUpdateMemberNamePerm || canUpdateMemberUntrustedMetadataPerm || canUpdateMemberIsBreakglassPerm || canUpdateMemberMfaEnrolledPerm || canUpdateMemberDefaultMfaMethodPerm || canUpdateMemberRolesPerm || canRevokeMemberSessionsPerm;
    const canUpdateSelf = canUpdateSelfNamePerm || canUpdateSelfUntrustedMetadataPerm || canUpdateSelfMfaPhonePerm || canDeleteSelfMfaPhonePerm || canDeleteSelfPasswordPerm || canUpdateSelfMfaEnrolledPerm || canUpdateSelfDefaultMfaMethodPerm || canDeleteSelfPerm || canDeleteSelfMfaTotpPerm || canRevokeSelfSessionsPerm;
    const canActivateOrDeactivate = canCreateMemberPerm || canDeleteMemberPerm;
    const orgInfo = useOrgInfo();
    const orgAllowsEmailInvites = orgInfo.data && orgInfo.data.email_invites !== 'NOT_ALLOWED';
    const { self } = useSelf();
    const currentMemberId = self?.member_id;
    const canInviteMember = canCreateMemberPerm && orgAllowsEmailInvites;
    const roleAutocompleteProps = useRoleAutocomplete({
        excludeStytchMember: true,
        includeOrgRoles: canGetOrgCustomRoles
    });
    const allRolesSet = useMemo(()=>new Set(roleAutocompleteProps.selectItems), [
        roleAutocompleteProps.selectItems
    ]);
    const allRolesFilterItems = useMemo(()=>{
        return roleAutocompleteProps.selectItems.map((roleId)=>({
                label: roleAutocompleteProps.getOptionLabel(roleId),
                value: roleId
            }));
    }, [
        roleAutocompleteProps
    ]);
    const [filterRoles, setFilterRoles] = usePersistentFilter({
        viewId: MEMBER_LIST_TABLE_VIEW_ID,
        fieldId: 'role',
        defaultValue: emptySet,
        permittedValues: allRolesSet
    });
    const [filterStatuses, setFilterStatuses] = usePersistentFilter({
        viewId: MEMBER_LIST_TABLE_VIEW_ID,
        fieldId: 'status',
        defaultValue: DEFAULT_STATUSES_FILTER,
        permittedValues: allMemberStatusesSet
    });
    const itemRenderer = useMemo(()=>[
            {
                id: 'name',
                title: 'Name',
                getValue: ({ name, member_id })=>{
                    return member_id === currentMemberId ? decorateCurrentMemberName(name) : name;
                },
                width: 200
            },
            {
                id: 'email',
                title: 'Email',
                getValue: ({ email_address })=>{
                    return email_address;
                },
                width: 200
            },
            {
                id: 'role',
                title: 'Role',
                getValue: ({ roles })=>{
                    return /*#__PURE__*/ React__default.createElement(RolesList, {
                        hideStytchMemberWithOtherRoles: true,
                        roles: roles
                    });
                },
                renderTitle: ()=>/*#__PURE__*/ React__default.createElement(ColumnTitleWithFilter, {
                        title: "Role",
                        items: allRolesFilterItems,
                        value: filterRoles,
                        onChange: setFilterRoles
                    })
            },
            {
                id: 'status',
                title: 'Status',
                getValue: ({ status })=>{
                    return getMemberStatusDisplayName(status);
                },
                renderTitle: ()=>/*#__PURE__*/ React__default.createElement(ColumnTitleWithFilter, {
                        title: "Status",
                        items: allStatusesFilterItems,
                        value: filterStatuses,
                        onChange: setFilterStatuses
                    }),
                width: 150
            }
        ], [
        allRolesFilterItems,
        currentMemberId,
        filterRoles,
        filterStatuses,
        setFilterRoles,
        setFilterStatuses
    ]);
    const [filterText, setFilterText, pendingFilterText] = useDebouncedState('');
    const [itemsPerPage, handleItemsPerPageChange] = useItemsPerPage({
        viewId: MEMBER_LIST_TABLE_VIEW_ID
    });
    const { data, error, isLoading, setSize, size, mutate } = useMembers({
        limit: itemsPerPage,
        email: filterText || undefined,
        roles: filterRoles.size > 0 ? Array.from(filterRoles) : undefined,
        statuses: filterStatuses.size > 0 ? Array.from(filterStatuses) : undefined
    });
    const resultsMetadata = data?.at(-1)?.results_metadata;
    // `size` is already effectively a page count, so we can act as if we only
    // have one item per page
    const { currentPage, setCurrentPage } = usePagination({
        itemsCount: size,
        itemsPerPage: 1
    });
    const tableProps = {
        currentPage,
        setCurrentPage,
        onRowClick: (id)=>navigate({
                screen: 'memberDetails',
                params: {
                    memberId: id
                }
            }),
        rowsPerPage: itemsPerPage,
        rowsPerPageOptions: itemsPerPageOptions,
        onRowsPerPageChange: handleItemsPerPageChange,
        items: useMemo(()=>data?.flatMap((page)=>page.members) ?? [], [
            data
        ]),
        loadNext: useCallback(()=>setSize((size)=>size + 1), [
            setSize
        ]),
        metadata: useMemo(()=>({
                cursor: resultsMetadata?.next_cursor ?? '__none',
                total: resultsMetadata?.total ?? 0
            }), [
            resultsMetadata?.next_cursor,
            resultsMetadata?.total
        ])
    };
    const { openToast } = useToast();
    const sendInviteEmail = useSendInviteEmail({
        onSuccess: mutate
    });
    const { handleInviteClick, inviteModalProps } = useInviteModal(sendInviteEmail);
    const handleEdit = useCallback((member)=>{
        navigate({
            screen: 'memberDetails',
            params: {
                memberId: member.member_id
            }
        });
    }, [
        navigate
    ]);
    const { openModal, modal } = useMemberActivation(mutate);
    const handleActivateDeactivateMember = useCallback((member)=>{
        openModal(member);
    }, [
        openModal
    ]);
    const actions = useMemo(()=>{
        const getDeleteAction = (member)=>{
            const isSelf = currentMemberId === member.member_id;
            switch(member.status){
                case 'invited':
                    if (canDeleteMemberPerm || canDeleteSelfPerm && isSelf) {
                        return 'revoke-invite';
                    }
                    break;
                case 'active':
                    if (canDeleteMemberPerm || canDeleteSelfPerm && isSelf) {
                        return 'deactivate';
                    }
                    break;
                case 'deleted':
                    if (canCreateMemberPerm && member.email_address_verified) {
                        return 'reactivate';
                    }
                    break;
            }
        };
        const canEdit = (member)=>{
            return (currentMemberId === member.member_id ? canUpdateSelf : canUpdateMember) ?? false;
        };
        return [
            {
                key: 'view',
                label: 'View member',
                icon: /*#__PURE__*/ React__default.createElement(VisibilityOutlined, null),
                onClick: handleEdit,
                isVisible: (member)=>!canEdit(member)
            },
            {
                key: 'edit',
                label: 'Edit member',
                icon: /*#__PURE__*/ React__default.createElement(EditOutlined, null),
                onClick: handleEdit,
                isVisible: (member)=>canEdit(member)
            },
            {
                key: 'resend-invite-email',
                label: 'Resend invite email',
                icon: /*#__PURE__*/ React__default.createElement(EmailOutlined, null),
                onClick: (member)=>sendInviteEmail(member.email_address).catch((error)=>{
                        const message = extractErrorMessage(error);
                        if (message) {
                            openToast({
                                text: message,
                                type: 'error'
                            });
                        }
                    }),
                isVisible: (member)=>Boolean(canInviteMember) && REINVITE_MEMBER_STATUS.has(member.status)
            },
            {
                key: 'revoke-invite',
                label: 'Revoke invite',
                icon: /*#__PURE__*/ React__default.createElement(DeleteOutlined, null),
                onClick: handleActivateDeactivateMember,
                isDangerous: true,
                isVisible: (member)=>getDeleteAction(member) === 'revoke-invite'
            },
            {
                key: 'deactivate',
                label: 'Deactivate',
                icon: /*#__PURE__*/ React__default.createElement(DeleteOutlined, null),
                onClick: handleActivateDeactivateMember,
                isDangerous: true,
                isVisible: (member)=>getDeleteAction(member) === 'deactivate'
            },
            {
                key: 'reactivate',
                label: 'Reactivate',
                icon: /*#__PURE__*/ React__default.createElement(CheckCircle, null),
                onClick: handleActivateDeactivateMember,
                isVisible: (member)=>getDeleteAction(member) === 'reactivate'
            }
        ];
    }, [
        canCreateMemberPerm,
        canDeleteMemberPerm,
        canDeleteSelfPerm,
        canInviteMember,
        canUpdateMember,
        canUpdateSelf,
        currentMemberId,
        handleActivateDeactivateMember,
        handleEdit,
        openToast,
        sendInviteEmail
    ]);
    const { getItemActionProps } = useActionMenu({
        actions,
        idPrefix: 'member',
        getId: getMemberId
    });
    return /*#__PURE__*/ React__default.createElement(FlexBox, {
        flexDirection: "column",
        gap: 3
    }, canActivateOrDeactivate && modal, /*#__PURE__*/ React__default.createElement(FlexBox, {
        alignItems: "center",
        justifyContent: "space-between"
    }, /*#__PURE__*/ React__default.createElement(Typography, {
        variant: "h1"
    }, "Members"), canInviteMember && /*#__PURE__*/ React__default.createElement(React__default.Fragment, null, /*#__PURE__*/ React__default.createElement(InviteModal, inviteModalProps), /*#__PURE__*/ React__default.createElement(Button, {
        compact: true,
        variant: "primary",
        startIcon: /*#__PURE__*/ React__default.createElement(Add, null),
        onClick: handleInviteClick
    }, "Invite"))), /*#__PURE__*/ React__default.createElement(SearchBar, {
        placeholder: "Search by email",
        value: pendingFilterText,
        onChange: setFilterText
    }), error ? /*#__PURE__*/ React__default.createElement(Alert, null, extractErrorMessage(error) ?? 'There was an error loading the Members list.') : /*#__PURE__*/ React__default.createElement(PaginatedTable, {
        ...tableProps,
        itemRenderer: itemRenderer,
        isLoading: isLoading,
        getItemActionProps: getItemActionProps,
        rowKeyExtractor: getMemberId,
        titleVariant: "h4"
    }));
};

export { MemberListScreen, useMembers };
//# sourceMappingURL=MemberListScreen.mjs.map
