'use client'
import { __awaiter } from '../../../../../_virtual/_tslib.js';
import { useMemo, useState, useCallback } from 'react';
import { ProviderEnum } from '@dynamic-labs/sdk-api-core';
import { SocialOAuthErrorCode } from '@dynamic-labs/types';
import { SocialAccountAlreadyExistsError, tracing, PlatformService, isMobile, Oauth2Service, DynamicError } from '@dynamic-labs/utils';
import { useCaptchaContext } from '../../../context/CaptchaContext/CaptchaContext.js';
import '../../../context/DynamicContext/DynamicContext.js';
import '../../../store/state/loadingAndLifecycle/loadingAndLifecycle.js';
import '@dynamic-labs/iconic';
import '@dynamic-labs/wallet-connector-core';
import 'react/jsx-runtime';
import '../../../context/ViewContext/ViewContext.js';
import { logger } from '../../../shared/logger.js';
import '@dynamic-labs/wallet-book';
import '../../constants/colors.js';
import '../../constants/values.js';
import '../../../shared/consts/index.js';
import { dynamicEvents } from '../../../events/dynamicEvents.js';
import { useErrorContext } from '../../../context/ErrorContext/ErrorContext.js';
import { digestSHA256 } from '../../functions/digestSHA256/digestSHA256.js';
import { encodeBase64URL } from '../../functions/encodeBase64URL/encodeBase64URL.js';
import '@dynamic-labs/multi-wallet';
import 'react-international-phone';
import { getOauthLoginUrl } from '../../functions/getOauthLoginUrl/getOauthLoginUrl.js';
import { setSocialStorageFor } from '../../functions/socialStorage/socialStorage.js';
import { getProviderByType } from '../../functions/getProviderByType/getProviderByType.js';
import { consumeNonce } from '../../../store/state/nonce/nonce.js';
import { randomString } from '../../functions/randomString/randomString.js';
import '@dynamic-labs-sdk/client/core';
import { getDynamicClient } from '../../../client/client.js';
import '@dynamic-labs-sdk/client';
import '../../../config/ApiEndpoint.js';
import { telegramSignIn, signInOAuth, telegramVerify, verifyOAuth, getOAuthResult, initAuth, farcasterSignIn, farcasterVerify } from '../../../data/api/oauth/oauth.js';
import '@dynamic-labs/locale';
import '../../../store/state/dynamicContextProps/dynamicContextProps.js';
import '../../../store/state/primaryWalletId/primaryWalletId.js';
import '../../../store/state/connectedWalletsInfo/connectedWalletsInfo.js';
import '../../../context/AccessDeniedContext/AccessDeniedContext.js';
import '../../../context/AccountExistsContext/AccountExistsContext.js';
import '../../../context/UserWalletsContext/UserWalletsContext.js';
import '../../../store/state/authMode/authMode.js';
import '../../../context/VerificationContext/VerificationContext.js';
import 'react-dom';
import '../../functions/compareChains/compareChains.js';
import '../../../views/Passkey/utils/findPrimaryEmbeddedChain/findPrimaryEmbeddedChain.js';
import { useEmbeddedWalletSessionKeys } from '../useEmbeddedWalletSessionKeys/useEmbeddedWalletSessionKeys.js';
import '../../../context/ThemeContext/ThemeContext.js';
import '../useUserUpdateRequest/useUpdateUser/userFieldsSchema.js';
import 'bs58';
import '../../../context/SocialRedirectContext/SocialRedirectContext.js';
import { useUserAuth } from '../useUserAuth/useUserAuth.js';
import { connect, watchStatus } from './farcaster/farcaster.js';
import 'yup';
import '../../../context/MockContext/MockContext.js';
import '../../../views/CollectUserDataView/useFields.js';
import '../../../context/FieldsStateContext/FieldsStateContext.js';
import '../../../context/UserFieldEditorContext/UserFieldEditorContext.js';
import '@dynamic-labs/rpc-providers';
import '../../../store/state/walletOptions/walletOptions.js';
import 'react-i18next';
import '../../../components/Accordion/components/AccordionItem/AccordionItem.js';
import '../../../components/Alert/Alert.js';
import '../../../context/WalletContext/WalletContext.js';
import '../../../components/ShadowDOM/ShadowDOM.js';
import '../../../components/IconButton/IconButton.js';
import '../../../components/InlineWidget/InlineWidget.js';
import '../../../components/Input/Input.js';
import '../../../components/IsBrowser/IsBrowser.js';
import '../../../components/MenuList/Dropdown/Dropdown.js';
import '../../../components/OverlayCard/OverlayCard.js';
import '../../../components/Transition/ZoomTransition/ZoomTransition.js';
import '../../../components/Transition/SlideInUpTransition/SlideInUpTransition.js';
import '../../../components/Transition/OpacityTransition/OpacityTransition.js';
import '../../../components/PasskeyCreatedSuccessBanner/PasskeyCreatedSuccessBanner.js';
import '../../../components/Popper/Popper/Popper.js';
import '../../../components/Popper/PopperContext/PopperContext.js';
import 'react-focus-lock';
import 'qrcode';
import 'formik';
import '../useSubdomainCheck/useSubdomainCheck.js';
import '../../../context/WalletGroupContext/WalletGroupContext.js';
import '../../../context/IpConfigurationContext/IpConfigurationContext.js';
import '../../../context/ConnectWithOtpContext/ConnectWithOtpContext.js';
import '../../../widgets/DynamicBridgeWidget/views/WalletsView/components/SecondaryWallets/SecondaryWallets.js';
import '@hcaptcha/react-hcaptcha';
import '../../../context/LoadingContext/LoadingContext.js';
import '../../../widgets/DynamicWidget/context/DynamicWidgetContext.js';
import '../../../widgets/DynamicWidget/helpers/convertExchangeKeyAndProviderEnum.js';
import '../../../views/ExchangeWhitelistWarning/ExchangeWhitelistWarning.js';
import '../../../context/ErrorContext/hooks/useErrorText/useErrorText.js';
import '../../../context/FooterAnimationContext/index.js';
import '../../../views/MfaChooseDeviceView/useGetMfaOptions/useGetMfaOptions.js';
import '../../../context/PasskeyContext/PasskeyContext.js';
import '../../../context/OnrampContext/OnrampContext.js';
import '../../../store/state/sendBalances.js';
import '../../../store/state/connectorsInitializing/connectorsInitializing.js';
import '../../../components/OverlayCardBase/OverlayCardTarget/OverlayCardTarget.js';
import '../../../widgets/DynamicWidget/components/DynamicWidgetHeader/DynamicWidgetHeader.js';
import '../../../views/TransactionConfirmationView/TransactionConfirmationView.js';
import '../../../widgets/DynamicWidget/components/PasskeyCard/PasskeyCard.js';
import '../useEmbeddedWallet/useSecureEnclaveEmbeddedWallet/constants.js';
import '../../../widgets/DynamicWidget/views/CryptoComOnramp/CryptoComOnramp.js';
import '../../../../index.js';
import '../../../widgets/DynamicWidget/views/ReceiveWalletFunds/ReceiveWalletFunds.js';
import '../../../store/state/tokenBalances.js';
import '../../../store/state/multichainBalances.js';
import '../../../shared/utils/functions/getInitialUrl/getInitialUrl.js';
import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';

const socialProviders = [
    'apple',
    'coinbasesocial',
    'discord',
    'epicgames',
    'facebook',
    'farcaster',
    'github',
    'google',
    'kraken',
    'line',
    'shopify',
    'spotify',
    'tiktok',
    'telegram',
    'twitch',
    'twitter',
];
// pkce params are only required for twitter and break if added for other providers, like google
// so we should only add provider that support pkce to this list
const providersRequiringPkce = ['twitter', 'github'];
// Hook to handle common social auth logic (for social linking and social sign in)
const useSocialAuth = ({ onSettled, onError, onFarcasterUrl, }) => {
    var _a;
    const { environmentId, setShowAuthFlow, socialSettings, projectSettings, redirectUrl: defaultRedirectUrl, } = useInternalDynamicContext();
    /**
     * Represents if the SDK will use a popup or redirect for social auth
     */
    const strategy = useMemo(() => (socialSettings === null || socialSettings === void 0 ? void 0 : socialSettings.strategy) || 'redirect', [socialSettings]);
    const { setErrorMessage, setError: setContextError } = useErrorContext();
    const { initAuth: initAuth$1 } = useUserAuth({
        authMethod: 'social',
    });
    const { generateSessionKey, shouldRegisterSessionKeysOnSignin } = useEmbeddedWalletSessionKeys({
        environmentId,
        projectSettings,
    });
    const [isProcessing, setIsProcessing] = useState(false);
    const [error, setError] = useState();
    const { engageCaptcha } = useCaptchaContext();
    const clearError = useCallback(() => {
        setError(undefined);
        setContextError(undefined);
    }, [setContextError]);
    const onFailed = useCallback((provider, reason, options) => {
        setIsProcessing(false);
        onError === null || onError === void 0 ? void 0 : onError();
        onSettled === null || onSettled === void 0 ? void 0 : onSettled();
        if (provider && (options === null || options === void 0 ? void 0 : options.raiseAuthFailure))
            dynamicEvents.emit('authFailure', {
                option: provider,
                provider,
                type: 'social',
            }, reason);
    }, [onError, onSettled]);
    const handleError = useCallback((provider, code, message, options) => {
        const error = { code, message };
        logger.error(message);
        setError(error);
        setErrorMessage(code);
        onFailed(provider, { error }, options);
    }, [onFailed, setErrorMessage]);
    const checkValidProvider = useCallback((provider, authMode) => {
        if (!provider) {
            handleError(provider, SocialOAuthErrorCode.NO_PROVIDER, 'Provider is required', { raiseAuthFailure: authMode === 'signin' });
            return false;
        }
        if (!socialProviders.includes(provider)) {
            handleError(provider, SocialOAuthErrorCode.INVALID_PROVIDER, `Invalid social provider. Valid providers are: ${socialProviders.join(', ')}`, { raiseAuthFailure: authMode === 'signin' });
            return false;
        }
        return true;
    }, [handleError]);
    const linkAccount = useCallback((provider, apiCall) => __awaiter(void 0, void 0, void 0, function* () {
        try {
            const response = yield apiCall();
            if (!response) {
                handleError(provider, SocialOAuthErrorCode.VERIFICATION_ERROR, `Failed to link social account: ${provider}`, { raiseAuthFailure: false });
                return;
            }
            onSettled === null || onSettled === void 0 ? void 0 : onSettled();
        }
        catch (error) {
            if (error instanceof SocialAccountAlreadyExistsError) {
                handleError(provider, SocialOAuthErrorCode.ACCOUNT_ALREADY_LINKED_TO_DIFFERENT_PROFILE, `Social account already linked to a different profile: ${provider}`, { raiseAuthFailure: false });
            }
        }
    }), [handleError, onSettled]);
    const signInAccount = useCallback((provider, apiCall) => __awaiter(void 0, void 0, void 0, function* () {
        yield initAuth$1({
            onError: () => handleError(provider, SocialOAuthErrorCode.SIGNIN_ERROR, `Failed to sign-in with social account: ${provider}`, { raiseAuthFailure: true }),
            onSettled,
            options: { provider },
            verifyFunction: () => apiCall(),
        });
    }), [handleError, initAuth$1, onSettled]);
    const completeConnection = useCallback((_b) => __awaiter(void 0, [_b], void 0, function* ({ authMode, provider, state, authCode, captchaToken, verifier, telegramAuthToken, forceCreateUser = false, ssoProviderId, }) {
        try {
            let sessionPublicKey = undefined;
            tracing.logEvent('oauth', 'completeConnection', tracing.formatObject({
                authMode,
                provider,
                shouldRegisterSessionKeysOnSignin: shouldRegisterSessionKeysOnSignin(),
            }));
            if (shouldRegisterSessionKeysOnSignin()) {
                const keypair = yield generateSessionKey();
                sessionPublicKey = keypair.publicKey;
                tracing.logEvent('oauth', 'completeConnection key generated', tracing.formatObject({
                    sessionPublicKey,
                }));
            }
            if (authMode === 'signin') {
                if (provider === ProviderEnum.Telegram && telegramAuthToken) {
                    const apiCall = () => telegramSignIn(environmentId, {
                        captchaToken,
                        forceCreateUser,
                        sessionPublicKey,
                        telegramAuthToken,
                    });
                    return yield signInAccount(provider, apiCall);
                }
                else if (provider === ProviderEnum.Telegram) {
                    const apiCall = () => telegramSignIn(environmentId, {
                        captchaToken,
                        code: authCode,
                        sessionPublicKey,
                        state,
                    });
                    yield signInAccount(provider, apiCall);
                }
                else {
                    const apiCall = () => signInOAuth(environmentId, provider, {
                        captchaToken,
                        code: authCode,
                        codeVerifier: verifier,
                        sessionPublicKey,
                        ssoProviderId,
                        state,
                    });
                    yield signInAccount(provider, apiCall);
                }
            }
            else {
                if (provider === ProviderEnum.Telegram) {
                    const apiCall = () => telegramVerify(environmentId, {
                        captchaToken,
                        code: authCode,
                        state,
                    });
                    yield linkAccount(provider, apiCall);
                }
                else {
                    const apiCall = () => verifyOAuth(environmentId, provider, {
                        code: authCode,
                        codeVerifier: verifier,
                        state,
                    });
                    yield linkAccount(provider, apiCall);
                }
            }
        }
        catch (error) {
            logger.error('Social connection failed with unexpected error:', error);
            onFailed(provider, { error }, { raiseAuthFailure: authMode === 'signin' });
        }
    }), [
        environmentId,
        generateSessionKey,
        linkAccount,
        onFailed,
        shouldRegisterSessionKeysOnSignin,
        signInAccount,
    ]);
    const connectWithFarcaster = useCallback((authMode_1, _c) => __awaiter(void 0, [authMode_1, _c], void 0, function* (authMode, { captchaToken, redirectUrl }) {
        let dynamicNonce;
        try {
            dynamicNonce = consumeNonce();
        }
        catch (error) {
            handleError(ProviderEnum.Farcaster, SocialOAuthErrorCode.GENERAL_ERROR, 'Missing nonce', { raiseAuthFailure: authMode === 'signin' });
            return;
        }
        const domain = PlatformService.getHost();
        const data = yield connect({
            domain,
            nonce: dynamicNonce,
            redirectUrl: redirectUrl || defaultRedirectUrl,
            siweUri: PlatformService.getOrigin(),
        });
        if (!(data === null || data === void 0 ? void 0 : data.url) || !(data === null || data === void 0 ? void 0 : data.channelToken)) {
            handleError(ProviderEnum.Farcaster, SocialOAuthErrorCode.GENERAL_ERROR, "Farcaster didn't return a valid url.", { raiseAuthFailure: authMode === 'signin' });
            return;
        }
        // If on mobile, we want to redirect to the Warpcast app.
        if (isMobile()) {
            yield PlatformService.openURL(data.url);
        }
        else {
            setShowAuthFlow(true);
            onFarcasterUrl === null || onFarcasterUrl === void 0 ? void 0 : onFarcasterUrl(data.url);
        }
        const statusResponse = yield watchStatus({
            channelToken: data.channelToken,
        });
        if (statusResponse.type === 'cancelled') {
            setIsProcessing(false);
            return;
        }
        if (statusResponse.type === 'timeout') {
            handleError(ProviderEnum.Farcaster, SocialOAuthErrorCode.GENERAL_ERROR, `Farcaster timed out while waiting for connection status. Error: ${statusResponse.error}`, { raiseAuthFailure: authMode === 'signin' });
            return;
        }
        if (!statusResponse.data.message ||
            !statusResponse.data.custody ||
            !statusResponse.data.signature ||
            !statusResponse.data.nonce) {
            handleError(ProviderEnum.Farcaster, SocialOAuthErrorCode.GENERAL_ERROR, `Farcaster returned invalid data. Expected to be defined: message, custody, signature, nonce. Received: ${JSON.stringify(statusResponse.data)}`, { raiseAuthFailure: authMode === 'signin' });
            return;
        }
        const { custody: address, message, signature, nonce, } = statusResponse.data;
        if (authMode === 'signin') {
            let sessionPublicKey = undefined;
            if (shouldRegisterSessionKeysOnSignin()) {
                const keypair = yield generateSessionKey();
                sessionPublicKey = keypair.publicKey;
            }
            const apiCall = () => farcasterSignIn(environmentId, {
                address,
                captchaToken,
                domain,
                message,
                nonce,
                sessionPublicKey,
                signature,
            });
            yield signInAccount(ProviderEnum.Farcaster, apiCall);
        }
        else {
            const apiCall = () => farcasterVerify({
                environmentId,
                farcasterSignInRequest: {
                    address,
                    captchaToken,
                    domain,
                    message,
                    nonce,
                    signature,
                },
            });
            yield linkAccount(ProviderEnum.Farcaster, apiCall);
            setShowAuthFlow(false, { clearErrors: false });
        }
        setIsProcessing(false);
    }), [
        defaultRedirectUrl,
        environmentId,
        generateSessionKey,
        handleError,
        linkAccount,
        onFarcasterUrl,
        setShowAuthFlow,
        shouldRegisterSessionKeysOnSignin,
        signInAccount,
    ]);
    const connectSocialAccount = useCallback((_d) => __awaiter(void 0, [_d], void 0, function* ({ authMode, provider, validator, captchaToken, isHeadlessSocialSignIn, payingWithDynamic, triggerFundFromExchangeOnSuccess, redirectUrl, telegramAuthToken, showWidgetAfterConnection, ssoProviderId, }) {
        var _e, _f;
        clearError();
        setIsProcessing(true);
        if (!authMode) {
            logger.error('Auth mode is required. Please use either "link" or "signin"');
            return;
        }
        if (!checkValidProvider(provider, authMode)) {
            return;
        }
        // invalid connect request
        if (validator && !validator(provider)) {
            return;
        }
        dynamicEvents.emit('authInit', {
            option: provider,
            provider,
            type: 'social',
        });
        if (provider === ProviderEnum.Farcaster) {
            return connectWithFarcaster(authMode, {
                captchaToken,
                redirectUrl,
            });
        }
        const state = randomString(32);
        const verifier = randomString(43);
        // Whether we will use PKCE (code verifier/challenge) for this provider
        const usingPkce = providersRequiringPkce.includes(provider);
        setSocialStorageFor(provider, {
            captchaToken,
            codeVerifier: usingPkce ? verifier : undefined,
            dynamicOauthSsoProviderId: ssoProviderId,
            isHeadlessSocialSignIn,
            mode: authMode,
            payingWithDynamic,
            showWidgetAfterConnection,
            state,
            triggerFundFromExchangeOnSuccess,
        });
        const loginUrlString = getOauthLoginUrl((_e = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _e !== void 0 ? _e : [], provider);
        if (!loginUrlString) {
            handleError(provider, SocialOAuthErrorCode.NO_OAUTH_URL, `Failed to get login url to connect social account: ${provider}`, { raiseAuthFailure: authMode === 'signin' });
            return;
        }
        const oauthLoginUrl = new URL(loginUrlString);
        oauthLoginUrl.searchParams.set('state', state);
        // only add pkce params for providers that support/require it
        if (usingPkce) {
            const digest = yield digestSHA256(verifier);
            oauthLoginUrl.searchParams.set('code_challenge', encodeBase64URL(digest));
            oauthLoginUrl.searchParams.set('code_challenge_method', 'S256');
        }
        const isMobile$1 = isMobile();
        try {
            const authCode = yield Oauth2Service.getOauthCode({
                apiProvider: getProviderByType((_f = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _f !== void 0 ? _f : [], provider),
                getOAuthResultFromApi: () => getOAuthResult(environmentId, provider, {
                    state,
                }),
                initWebAuth: ({ redirectUrl } = {}) => initAuth(environmentId, provider, {
                    redirectUrl: redirectUrl
                        ? removeDynamicOauthParamsFromUrl(redirectUrl)
                        : undefined,
                    state,
                }),
                isMobile: isMobile$1,
                oauthLoginUrl,
                onSettled,
                provider,
                redirectUrl: redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : defaultRedirectUrl,
                setIsProcessing,
                state,
                strategy,
            });
            yield completeConnection({
                authCode,
                authMode,
                captchaToken,
                provider,
                ssoProviderId,
                state,
                telegramAuthToken,
                verifier,
            });
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
        }
        catch (error) {
            if (Oauth2Service.isGetOauthCodeError(error)) {
                handleError(provider, error.code, error.message, {
                    raiseAuthFailure: authMode === 'signin',
                });
                return;
            }
            // Log message individually so the Expo console can display it (it fails to display objects)
            logger.error('Social connection failed with unexpected error:', error.message, error);
            onFailed(provider, { error }, { raiseAuthFailure: authMode === 'signin' });
        }
    }), [
        checkValidProvider,
        clearError,
        completeConnection,
        connectWithFarcaster,
        defaultRedirectUrl,
        environmentId,
        handleError,
        onFailed,
        onSettled,
        projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers,
        strategy,
    ]);
    const checkCaptchaAndConnect = useCallback((props) => __awaiter(void 0, void 0, void 0, function* () {
        var _g;
        if (props.authMode === 'signin' && getDynamicClient().user) {
            throw new DynamicError('User is already logged in');
        }
        else if (props.authMode === 'link' && !getDynamicClient().user) {
            throw new DynamicError('User is not logged in');
        }
        if (!((_g = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.security.hCaptcha) === null || _g === void 0 ? void 0 : _g.enabled)) {
            connectSocialAccount(props);
            return;
        }
        // Make sure the auth flow is visible
        // it would still be hidden in headless scenarios
        setShowAuthFlow(true, {
            initializeWalletConnect: false,
            performMultiWalletChecks: false,
        });
        engageCaptcha({
            authMethod: 'social',
            onCaptchaSuccess: (captchaToken) => __awaiter(void 0, void 0, void 0, function* () {
                connectSocialAccount(Object.assign(Object.assign({}, props), { captchaToken }));
                setShowAuthFlow(false);
            }),
        });
    }), [
        setShowAuthFlow,
        connectSocialAccount,
        engageCaptcha,
        (_a = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.security.hCaptcha) === null || _a === void 0 ? void 0 : _a.enabled,
    ]);
    return useMemo(() => ({
        checkValidProvider,
        completeConnection,
        connectSocialAccount: checkCaptchaAndConnect,
        error,
        handleError,
        isProcessing,
        setError,
        setIsProcessing,
    }), [
        checkValidProvider,
        completeConnection,
        checkCaptchaAndConnect,
        error,
        handleError,
        isProcessing,
    ]);
};
const removeDynamicOauthParamsFromUrl = (url) => {
    const urlObject = new URL(url);
    urlObject.searchParams.delete('dynamicOauthState');
    urlObject.searchParams.delete('dynamicOauthCode');
    return urlObject.toString();
};

export { useSocialAuth };
