import React__default, { useMemo, useRef, useCallback, useState } from 'react';
import { Autocomplete } from '../components/Autocomplete.mjs';
import { FlexBox } from '../shared/components/FlexBox.mjs';
import { ListEditor } from '../components/ListEditor.mjs';
import { Modal } from '../components/Modal.mjs';
import { SettingsContainer, useSettingsContainer } from '../components/SettingsContainer.mjs';
import { SettingsSection } from '../components/SettingsSection.mjs';
import { Switch } from '../components/Switch.mjs';
import { Typography } from '../components/Typography.mjs';
import { arraysHaveSameContents } from '../utils/arraysHaveSameContents.mjs';
import { ROLE_ID_STYTCH_MEMBER } from '../utils/roles.mjs';
import { useFormState } from '../utils/useFormState.mjs';
import { useMutateMember } from '../utils/useMutateMember.mjs';
import { useRbac } from '../utils/useRbac.mjs';
import { useRoleAutocomplete } from '../utils/useRoleAutocomplete.mjs';
import { useRoleDisplayInfo } from '../utils/useRoleDisplayInfo.mjs';
import { useRoles } from '../utils/useRoles.mjs';
import { useRoleSortFn } from '../utils/useRoleSortFn.mjs';
import { useSelf } from '../utils/useSelf.mjs';
import { useStateSliceSetter } from '../utils/useStateSliceSetter.mjs';
import { useMemberManagementRouterController } from './MemberManagementRouter.mjs';
import { useModalState } from '../shared/components/Modal.mjs';

const getRoleSourceTypeDisplayName = (sourceType)=>{
    switch(sourceType){
        case 'direct_assignment':
            return 'Manual assignment';
        case 'email_assignment':
            return 'Email domain';
        case 'sso_connection':
            return 'SSO connection';
        case 'sso_connection_group':
            return 'SSO group';
        case 'scim_connection_group':
            return 'SCIM group';
        default:
            return sourceType;
    }
};
const roleAssignmentsRowKeyExtractor = (item)=>`${item.role_id}-${item.sourceType}`;
const AccessSectionBody = ({ localState, setLocalState, remoteState, implicitRoleAssignments, showRoleAssignment, isSelf, orgRequiresMfa })=>{
    const { editing } = useSettingsContainer();
    const { isMfaEnrolled, explicitRoleAssignments, isBreakglass } = editing ? localState : remoteState;
    const handleIsMfaEnrolledChange = useStateSliceSetter(setLocalState, 'isMfaEnrolled');
    const setIsBreakglass = useStateSliceSetter(setLocalState, 'isBreakglass');
    const { open: openBreakGlassConfirmModal, ...breakGlassConfirmModalProps } = useModalState(()=>{
        setIsBreakglass(true);
    });
    const handleIsBreakglassChange = useCallback((value)=>{
        if (value) {
            openBreakGlassConfirmModal();
        } else {
            setIsBreakglass(value);
        }
    }, [
        openBreakGlassConfirmModal,
        setIsBreakglass
    ]);
    const { data: canUpdateMemberRolesPerm } = useRbac('stytch.member', 'update.settings.roles');
    const { data: canUpdateMemberMfaEnrolledPerm } = useRbac('stytch.member', 'update.settings.mfa-enrolled');
    const { data: canUpdateMemberBreakglassPerm } = useRbac('stytch.member', 'update.settings.is-breakglass');
    const { data: canUpdateSelfMfaEnrolledPerm } = useRbac('stytch.self', 'update.settings.mfa-enrolled');
    const { data: canGetOrgCustomRoles } = useRbac('stytch.custom-org-roles', 'get');
    const canUpdateMfaEnrolled = canUpdateMemberMfaEnrolledPerm || canUpdateSelfMfaEnrolledPerm && isSelf;
    const canUpdateRoles = canUpdateMemberRolesPerm;
    const canUpdateBreakglass = canUpdateMemberBreakglassPerm;
    const sortRoles = useRoleSortFn();
    const { selectItems: roleSelectItems, ...roleAutocompleteProps } = useRoleAutocomplete({
        excludeStytchMember: true,
        includeOrgRoles: canGetOrgCustomRoles
    });
    const availableRoleSelectItems = roleSelectItems.filter((roleId)=>!explicitRoleAssignments.includes(roleId));
    const { getRoleIdDisplayName } = useRoleDisplayInfo(canGetOrgCustomRoles);
    const stytchMemberRoleDisplayName = roleAutocompleteProps.getOptionLabel(ROLE_ID_STYTCH_MEMBER);
    const combinedRoleAssignments = useMemo(()=>{
        return [
            ...sortRoles(implicitRoleAssignments),
            ...sortRoles(explicitRoleAssignments.map((roleId)=>({
                    role_id: roleId,
                    sourceType: 'direct_assignment'
                })))
        ];
    }, [
        explicitRoleAssignments,
        implicitRoleAssignments,
        sortRoles
    ]);
    const [pendingAssignments, setPendingAssignments] = useState([]);
    const { open: openRoleAssignmentModal, ...roleAssignmentModalProps } = useModalState(()=>{
        setLocalState((state)=>{
            return {
                ...state,
                explicitRoleAssignments: Array.from(new Set([
                    ...state.explicitRoleAssignments,
                    ...pendingAssignments
                ]))
            };
        });
    });
    const roleAssignmentsItemRenderer = useMemo(()=>[
            {
                title: 'Role',
                getValue: (assignment)=>/*#__PURE__*/ React__default.createElement(Typography, {
                        variant: "body2"
                    }, getRoleIdDisplayName(assignment.role_id))
            },
            {
                title: 'Source',
                getValue: (assignment)=>/*#__PURE__*/ React__default.createElement(Typography, {
                        variant: "body2"
                    }, getRoleSourceTypeDisplayName(assignment.sourceType))
            }
        ], [
        getRoleIdDisplayName
    ]);
    const handleAddRoleAssignment = useCallback(()=>{
        setPendingAssignments([]);
        openRoleAssignmentModal();
    }, [
        openRoleAssignmentModal
    ]);
    const roleAssignmentsItemActionProps = useMemo(()=>(item)=>item.sourceType === 'direct_assignment' ? {
                warningAction: {
                    text: 'Revoke',
                    onClick: ()=>{
                        setLocalState((state)=>{
                            return {
                                ...state,
                                explicitRoleAssignments: state.explicitRoleAssignments.filter((roleId)=>roleId !== item.role_id)
                            };
                        });
                    }
                }
            } : {}, [
        setLocalState
    ]);
    return /*#__PURE__*/ React__default.createElement(FlexBox, {
        flexDirection: "column",
        gap: 2
    }, editing && /*#__PURE__*/ React__default.createElement(Modal, {
        ...breakGlassConfirmModalProps,
        title: "Exempt Member from primary auth requirements?",
        confirmButtonText: "Allow",
        warning: true
    }, /*#__PURE__*/ React__default.createElement(Typography, null, "Enabling this toggle will exempt the Member from your primary authentication policy if needed (e.g. to update SSO configuration in the case of a lockout).")), showRoleAssignment && /*#__PURE__*/ React__default.createElement(SettingsSection, {
        title: "Role assignments"
    }, /*#__PURE__*/ React__default.createElement(Modal, {
        ...roleAssignmentModalProps,
        title: "Add Role assignment",
        confirmButtonText: "Add Role"
    }, /*#__PURE__*/ React__default.createElement(FlexBox, {
        flexDirection: "column",
        gap: 0.5
    }, /*#__PURE__*/ React__default.createElement(Typography, {
        color: "secondary",
        variant: "caption"
    }, "Role"), /*#__PURE__*/ React__default.createElement(Autocomplete, {
        ...roleAutocompleteProps,
        selectItems: availableRoleSelectItems,
        value: pendingAssignments,
        onChange: setPendingAssignments,
        placeholder: pendingAssignments.length > 0 ? undefined : 'Select Role'
    }))), /*#__PURE__*/ React__default.createElement(Typography, {
        variant: "body2"
    }, "All members are automatically assigned the ", stytchMemberRoleDisplayName, " Role."), /*#__PURE__*/ React__default.createElement(ListEditor, {
        items: combinedRoleAssignments,
        rowKeyExtractor: roleAssignmentsRowKeyExtractor,
        itemRenderer: roleAssignmentsItemRenderer,
        addButtonText: "Add Role assignment",
        hideAddButton: availableRoleSelectItems.length === 0,
        readOnly: !(editing && canUpdateRoles),
        onAdd: handleAddRoleAssignment,
        getItemActionProps: roleAssignmentsItemActionProps
    })), /*#__PURE__*/ React__default.createElement(SettingsSection, {
        title: "Require MFA"
    }, orgRequiresMfa ? /*#__PURE__*/ React__default.createElement(Typography, {
        variant: "body2"
    }, "MFA is required for all members.") : /*#__PURE__*/ React__default.createElement(Switch, {
        readOnly: !editing || !canUpdateMfaEnrolled,
        checked: isMfaEnrolled,
        onChange: handleIsMfaEnrolledChange,
        label: "Require MFA for this Member. When enabled, the Member will be required to set up and use MFA on each login."
    })), /*#__PURE__*/ React__default.createElement(SettingsSection, {
        title: "Exempt from primary auth requirements"
    }, /*#__PURE__*/ React__default.createElement(Switch, {
        readOnly: !editing || !canUpdateBreakglass,
        checked: isBreakglass,
        onChange: handleIsBreakglassChange,
        label: "Exempt Member from your primary authentication policy"
    })));
};
const rolesCanUpdateMemberRoles = (roleIds, roles)=>{
    return Array.from(new Set(roleIds)).some((roleId)=>{
        const role = roles.find((role)=>role.role_id === roleId);
        return role?.permissions.some((permission)=>permission.resource_id === 'stytch.member' && (permission.actions.includes('update.settings.roles') || permission.actions.includes('*')));
    });
};
const AccessSection = ({ member, orgRequiresMfa })=>{
    const { isSelf } = useSelf();
    const isMemberSelf = isSelf(member.member_id);
    const { data: canUpdateMemberRolesPerm } = useRbac('stytch.member', 'update.settings.roles');
    const { data: canUpdateMemberBreakglassPerm } = useRbac('stytch.member', 'update.settings.is-breakglass');
    const { data: canUpdateMemberMfaEnrolledPerm } = useRbac('stytch.member', 'update.settings.mfa-enrolled');
    const { data: canUpdateSelfMfaEnrolledPerm } = useRbac('stytch.self', 'update.settings.mfa-enrolled');
    const { data: canGetOrgCustomRoles } = useRbac('stytch.custom-org-roles', 'get');
    const canUpdateRoles = canUpdateMemberRolesPerm;
    const canUpdateBreakglass = canUpdateMemberBreakglassPerm;
    const canUpdateMfaEnrolled = !orgRequiresMfa && (canUpdateMemberMfaEnrolledPerm || canUpdateSelfMfaEnrolledPerm && isMemberSelf);
    const isMemberDeleted = member.status === 'deleted';
    const canEditSection = !isMemberDeleted && (canUpdateRoles || canUpdateBreakglass || canUpdateMfaEnrolled);
    const showRoleAssignment = !isMemberDeleted;
    const { explicitRoleAssignments, implicitRoleAssignments } = useMemo(()=>{
        return member.roles.filter((role)=>role.role_id !== ROLE_ID_STYTCH_MEMBER).reduce((acc, role)=>{
            const implicitAssignments = new Set(role.sources.filter((source)=>source.type !== 'direct_assignment').map((source)=>source.type));
            for (const sourceType of implicitAssignments){
                acc.implicitRoleAssignments.push({
                    role_id: role.role_id,
                    sourceType
                });
            }
            const isExplicitAssignment = role.sources.some((source)=>source.type === 'direct_assignment');
            if (isExplicitAssignment) {
                acc.explicitRoleAssignments.push(role.role_id);
            }
            return acc;
        }, {
            explicitRoleAssignments: [],
            implicitRoleAssignments: []
        });
    }, [
        member.roles
    ]);
    const remoteState = useMemo(()=>({
            isMfaEnrolled: member.mfa_enrolled,
            explicitRoleAssignments,
            isBreakglass: member.is_breakglass
        }), [
        explicitRoleAssignments,
        member.is_breakglass,
        member.mfa_enrolled
    ]);
    const { localState, setLocalState, editing, handleSetEditing } = useFormState({
        remoteState
    });
    const { mutate } = useMutateMember();
    const lockoutConfirmDeferred = useRef();
    const { open: openLockoutWarningModal, close: closeLockoutWarningModal, ...lockoutWarningModalProps } = useModalState(()=>{
        lockoutConfirmDeferred.current?.resolve();
        lockoutConfirmDeferred.current = undefined;
    });
    const handleLockoutWarningCancel = useCallback(()=>{
        lockoutConfirmDeferred.current?.reject();
        lockoutConfirmDeferred.current = undefined;
        closeLockoutWarningModal();
    }, [
        closeLockoutWarningModal
    ]);
    const roles = useRoles(canGetOrgCustomRoles);
    const handleSave = useCallback(async ()=>{
        const memberOptions = {
            member_id: member.member_id
        };
        let shouldUpdate = false;
        const setOption = (key, value)=>{
            memberOptions[key] = value;
            shouldUpdate = true;
        };
        if (localState.isMfaEnrolled !== remoteState.isMfaEnrolled) {
            setOption('mfa_enrolled', localState.isMfaEnrolled);
        }
        if (localState.isBreakglass !== remoteState.isBreakglass) {
            setOption('is_breakglass', localState.isBreakglass);
        }
        if (!arraysHaveSameContents(localState.explicitRoleAssignments, remoteState.explicitRoleAssignments)) {
            if (isSelf(member.member_id) && roles && !rolesCanUpdateMemberRoles([
                ...localState.explicitRoleAssignments,
                ...implicitRoleAssignments.map((role)=>role.role_id)
            ], roles)) {
                openLockoutWarningModal();
                await new Promise((resolve, reject)=>{
                    lockoutConfirmDeferred.current = {
                        resolve,
                        reject
                    };
                });
            }
            setOption('roles', localState.explicitRoleAssignments);
        }
        if (shouldUpdate) {
            await mutate(memberOptions);
        }
    }, [
        implicitRoleAssignments,
        isSelf,
        localState.explicitRoleAssignments,
        localState.isBreakglass,
        localState.isMfaEnrolled,
        member.member_id,
        mutate,
        openLockoutWarningModal,
        remoteState.explicitRoleAssignments,
        remoteState.isBreakglass,
        remoteState.isMfaEnrolled,
        roles
    ]);
    const { useBlockNavigation } = useMemberManagementRouterController();
    return /*#__PURE__*/ React__default.createElement(SettingsContainer, {
        title: "Access requirements & permissions",
        hasCTA: canEditSection,
        onSave: handleSave,
        useBlockNavigation: useBlockNavigation,
        editing: editing,
        setEditing: handleSetEditing
    }, /*#__PURE__*/ React__default.createElement(Modal, {
        ...lockoutWarningModalProps,
        close: handleLockoutWarningCancel,
        title: "Revoke Role assignments?",
        confirmButtonText: "Revoke",
        warning: true
    }, /*#__PURE__*/ React__default.createElement(Typography, null, "Changing your Role assignments will remove your permissions to manage members. You will not be able to edit your Role assignments to reassign permissions.")), /*#__PURE__*/ React__default.createElement(AccessSectionBody, {
        remoteState: remoteState,
        localState: localState,
        setLocalState: setLocalState,
        implicitRoleAssignments: implicitRoleAssignments,
        showRoleAssignment: showRoleAssignment,
        isSelf: isMemberSelf,
        orgRequiresMfa: orgRequiresMfa
    }));
};

export { AccessSection };
//# sourceMappingURL=AccessSection.mjs.map
