import { useLingui } from '../../../../../../node_modules/@lingui/react/dist/index.mjs';
import React__default, { useReducer, useEffect, useCallback, useMemo } from 'react';
import { fallbackConsentManifestGenerator, createCustomScopeDescriptions, containsCustomScopes } from '../../../utils/idpHelpers.mjs';
import Button from '../atoms/Button.mjs';
import Column from '../atoms/Column.mjs';
import Logo from '../atoms/Logo.mjs';
import Typography from '../atoms/Typography.mjs';
import ButtonColumn from '../molecules/ButtonColumn.mjs';
import { Confirmation } from '../molecules/Confirmation.mjs';
import { ErrorDisplay } from '../molecules/ErrorScreen.mjs';
import { LoadingScreen } from '../molecules/Loading.mjs';
import { usePresentation } from '../PresentationConfig.mjs';
import { UngrantableScopes, ConsentManifest } from './IDPConsentManifest.mjs';
import { useConsentManifestGenerator } from './IDPContextProvider.mjs';
import { IDPOAuthFlowMissingParamError, StytchAPIError } from '../../../../../core/src/public/SDKErrors.mjs';
import { StytchEventType } from '../../../../../core/src/public/ui.mjs';
import { logger } from '../../../../../core/src/utils/logger.mjs';

const initialState$1 = (error, params)=>({
        loading: !error,
        preflight: !!error,
        error: error,
        success: false,
        denied: false,
        consent_required: false,
        client: null,
        grantable_scope: '',
        ungrantable_scope: '',
        redirect_uri: params.redirect_uri
    });
const idpStateReducer = (state, action)=>{
    switch(action.type){
        case 'START_SUBMIT':
            return {
                ...state,
                loading: true
            };
        case 'COMPLETE_SUBMIT':
            return {
                ...state,
                loading: false,
                success: true
            };
        case 'START_PREFLIGHT':
            return {
                ...state,
                preflight: true,
                loading: true
            };
        case 'PREFLIGHT_ERROR':
            return {
                ...state,
                preflight: true,
                loading: false,
                error: action.error
            };
        case 'COMPLETE_PREFLIGHT':
            return {
                ...state,
                loading: false,
                client: action.client,
                consent_required: action.consent_required,
                grantable_scope: action.grantable_scope,
                ungrantable_scope: action.ungrantable_scope
            };
        case 'CONSENT_DENIED':
            return {
                ...state,
                denied: true
            };
        default:
            return state;
    }
};
const useIDPState = ({ initialError, initialParams, oauthAuthorizeStart, oauthAuthorizeSubmit, onError, onEvent })=>{
    const [state, dispatch] = useReducer(idpStateReducer, initialState$1(initialError, initialParams));
    useEffect(()=>{
        if (!initialError) return;
        onError(new IDPOAuthFlowMissingParamError(initialError));
    }, [
        initialError,
        onError
    ]);
    const submitInternal = useCallback(async ({ consent_required, consent_granted })=>{
        dispatch({
            type: 'START_SUBMIT'
        });
        const submitResp = await oauthAuthorizeSubmit({
            ...initialParams,
            consent_granted
        });
        if (submitResp.authorization_code) {
            dispatch({
                type: 'COMPLETE_SUBMIT'
            });
        }
        window.location.href = submitResp.redirect_uri;
        if (consent_required && !consent_granted) {
            dispatch({
                type: 'CONSENT_DENIED'
            });
            onEvent({
                type: StytchEventType.OAuthAuthorizeFlowConsentDenied,
                data: {}
            });
        } else {
            onEvent({
                type: StytchEventType.OAuthAuthorizeFlowComplete,
                data: {}
            });
        }
    }, [
        oauthAuthorizeSubmit,
        initialParams,
        onEvent
    ]);
    const submit = useCallback(({ consent_granted })=>submitInternal({
            consent_granted,
            consent_required: true
        }), [
        submitInternal
    ]);
    const loadClient = useCallback(async ()=>{
        dispatch({
            type: 'START_PREFLIGHT'
        });
        onEvent({
            type: StytchEventType.OAuthAuthorizeFlowStart,
            data: {
                client_id: initialParams['client_id'],
                redirect_uri: initialParams['redirect_uri'],
                scope: initialParams['scopes'].join(' ')
            }
        });
        let startResponse;
        try {
            startResponse = await oauthAuthorizeStart(initialParams);
        } catch (e) {
            const err = StytchAPIError.from(e);
            const message = err.error_message;
            dispatch({
                type: 'PREFLIGHT_ERROR',
                error: message
            });
            onError(err);
            return;
        }
        if (startResponse.consent_required) {
            const grantable = startResponse.scope_results.filter((s)=>s.is_grantable).map((s)=>s.scope).join(' ');
            const ungrantable = startResponse.scope_results.filter((s)=>!s.is_grantable).map((s)=>s.scope).join(' ');
            dispatch({
                type: 'COMPLETE_PREFLIGHT',
                consent_required: startResponse.consent_required,
                client: startResponse.client,
                grantable_scope: grantable,
                ungrantable_scope: ungrantable
            });
            return;
        } else {
            await submitInternal({
                consent_required: false,
                consent_granted: false
            });
        }
    }, [
        onEvent,
        initialParams,
        oauthAuthorizeStart,
        onError,
        submitInternal
    ]);
    useEffect(()=>{
        if (state.preflight) {
            return;
        }
        loadClient();
    }, [
        loadClient,
        state.preflight
    ]);
    return {
        state,
        submit
    };
};
const IDPConsent = ({ bootstrap, bootstrapNotLoaded, state, submit })=>{
    const { i18n: $__i18n, _: $__ } = useLingui();
    const { loading, error, denied, success, client } = state;
    const customConsentManifestGenerator = useConsentManifestGenerator();
    const clientName = useMemo(()=>{
        let name = state.client?.client_name ?? '';
        // If a client name isn't provided then try and parse it from the
        // redirect URI domain.
        if (!name) {
            try {
                const u = new URL(state.redirect_uri);
                name = u.hostname;
            } catch (e) {
                logger.warn('Unable to parse host from redirect URI.', e);
                name = $__i18n._({
                    id: "idpConsent.defaultClientName",
                    message: "The App"
                });
            }
        }
        return name;
    }, [
        state.client?.client_name,
        state.redirect_uri,
        $__
    ]);
    const manifest = useMemo(()=>{
        if (customConsentManifestGenerator) {
            try {
                return customConsentManifestGenerator({
                    scopes: state.grantable_scope.split(' '),
                    clientName
                });
            } catch (e) {
                logger.error('Error rendering custom consent screen. Falling back to default consent screen.', e);
            }
        }
        return fallbackConsentManifestGenerator({
            scopes: state.grantable_scope.split(' '),
            rbacPolicy: bootstrap.rbacPolicy,
            clientName
        });
    }, [
        customConsentManifestGenerator,
        state.grantable_scope,
        clientName,
        bootstrap.rbacPolicy
    ]);
    const ungrantableScopeDescriptions = useMemo(()=>{
        if (state.ungrantable_scope === '') return [];
        return createCustomScopeDescriptions(state.ungrantable_scope.split(' '), bootstrap.rbacPolicy);
    }, [
        state.ungrantable_scope,
        bootstrap.rbacPolicy
    ]);
    if (loading || bootstrapNotLoaded) {
        return /*#__PURE__*/ React__default.createElement(LoadingScreen, null);
    }
    if (error) {
        return /*#__PURE__*/ React__default.createElement(ErrorDisplay, {
            text: error
        });
    }
    if (denied) {
        return /*#__PURE__*/ React__default.createElement(ErrorDisplay, {
            text: $__i18n._({
                id: "idpConsent.denied",
                message: "Access to the application was denied."
            })
        });
    }
    if (success) {
        return /*#__PURE__*/ React__default.createElement(Confirmation, null);
    }
    return /*#__PURE__*/ React__default.createElement(Consent, {
        client: client,
        submit: submit,
        grantableScope: state.grantable_scope,
        projectName: bootstrap.projectName
    }, /*#__PURE__*/ React__default.createElement(UngrantableScopes, {
        ungrantableScopeDescriptions: ungrantableScopeDescriptions,
        clientName: clientName
    }), /*#__PURE__*/ React__default.createElement(ConsentManifest, {
        manifest: manifest,
        clientName: clientName
    }));
};
const Consent = ({ client, submit, grantableScope, projectName, children })=>{
    const { i18n: $__i18n, _: $__ } = useLingui();
    const { options } = usePresentation();
    const clientName = client.client_name;
    const title = containsCustomScopes(grantableScope) ? $__i18n._({
        id: "idpConsent.customScopes.title",
        message: "{clientName} wants to access your {projectName} account",
        values: {
            clientName: clientName,
            projectName: projectName
        }
    }) : $__i18n._({
        id: "idpConsent.signIn.title",
        message: "Sign in to {clientName} with {projectName}",
        values: {
            clientName: clientName,
            projectName: projectName
        }
    });
    return /*#__PURE__*/ React__default.createElement(Column, {
        gap: 6
    }, options.logo && /*#__PURE__*/ React__default.createElement(Logo, {
        appLogo: options.logo
    }), /*#__PURE__*/ React__default.createElement(Typography, {
        variant: "header",
        align: "center"
    }, title), children, /*#__PURE__*/ React__default.createElement(ButtonColumn, null, /*#__PURE__*/ React__default.createElement(Button, {
        variant: "primary",
        onClick: ()=>submit({
                consent_granted: true
            })
    }, $__i18n._({
        id: "idpConsent.button.allow",
        message: "Allow"
    })), /*#__PURE__*/ React__default.createElement(Button, {
        onClick: ()=>submit({
                consent_granted: false
            }),
        variant: "ghost"
    }, $__i18n._({
        id: "idpConsent.button.deny",
        message: "Deny"
    }))));
};

export { IDPConsent, useIDPState };
//# sourceMappingURL=IDPConsent.mjs.map
