'use client'
import { __awaiter } from '../../../../../_virtual/_tslib.js';
import { DynamicError, StorageService, EmbeddedWalletExistsError, WalletUsedError, MergeAccountsConfirmationError, ChainalysisError, GateBlockedError, SandboxMaximumThresholdReachedError, NoAccessError, AccountExistsError } from '@dynamic-labs/utils';
import { getWalletProvider, isSocialWalletConnector } from '@dynamic-labs/wallet-connector-core';
import 'react';
import { dynamicEvents } from '../../../events/dynamicEvents.js';
import '../../../context/DynamicContext/DynamicContext.js';
import '../../../store/state/loadingAndLifecycle/loadingAndLifecycle.js';
import '@dynamic-labs/iconic';
import 'react/jsx-runtime';
import { useViewContext } from '../../../context/ViewContext/ViewContext.js';
import { logger } from '../../../shared/logger.js';
import '@dynamic-labs/wallet-book';
import { LAST_USED_WALLET } from '../../constants/localStorage.js';
import '../../constants/colors.js';
import '../../constants/values.js';
import '@dynamic-labs/sdk-api-core';
import '../../../shared/consts/index.js';
import { setAuthMode, getAuthMode } from '../../../store/state/authMode/authMode.js';
import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
import '../../../context/CaptchaContext/CaptchaContext.js';
import { useErrorContext } from '../../../context/ErrorContext/ErrorContext.js';
import { USER_NOT_LOGGED_IN } from '../../constants/errors.js';
import '@dynamic-labs/multi-wallet';
import 'react-international-phone';
import { getVerifyArgs } from '../../functions/getVerifyArgs/getVerifyArgs.js';
import { updatePrimaryWalletId } from '../../functions/updatePrimaryWalletId/updatePrimaryWalletId.js';
import { resetConnectedWalletsInfo } from '../../../store/state/connectedWalletsInfo/connectedWalletsInfo.js';
import '../../../store/state/dynamicContextProps/dynamicContextProps.js';
import '../../../store/state/primaryWalletId/primaryWalletId.js';
import { generateClientSessionKeys } from '../../functions/clientSessionKeys/getClientSessionKeys.js';
import '@dynamic-labs-sdk/client/core';
import '../../../client/client.js';
import '@dynamic-labs-sdk/client';
import '../../../config/ApiEndpoint.js';
import '@dynamic-labs/locale';
import { verifyWallet, linkWallet } from '../../../data/api/wallets/wallets.js';
import { useAccessDeniedContext } from '../../../context/AccessDeniedContext/AccessDeniedContext.js';
import { useAccountExistsContext } from '../../../context/AccountExistsContext/AccountExistsContext.js';
import { useInternalUserWallets } from '../../../context/UserWalletsContext/UserWalletsContext.js';
import { getSiweStatement } from '../../functions/getSiweStatement/getSiweStatement.js';
import '../../../context/VerificationContext/VerificationContext.js';
import '../../../store/state/nonce/nonce.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 '@dynamic-labs/types';
import '../../../context/SocialRedirectContext/SocialRedirectContext.js';
import { useUserAuth } from '../useUserAuth/useUserAuth.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';

// This logic is used to both verify or link a wallet
// Since we are re-using the different screens to authenticate or link the wallet.
// This logic is the best place to determine whether we should verify or verify and link.
const useVerifyWallet = ({ displaySiweStatement, environmentId, projectSettings, setIsSingleWalletAccount, }) => {
    const { setExistentAccountData } = useAccountExistsContext();
    const { setDeniedAddress, setDeniedOauthProvider } = useAccessDeniedContext();
    const { pushView, clearStackAndPushInitialView } = useViewContext();
    const { setErrorMessage, setError } = useErrorContext();
    const { multiWalletWidgetState, debugError, multiWallet: multiWalletEnabled, appName, primaryWalletId, setShowAuthFlow, siweStatement, connectedWallets, user, events, primaryWallet, enableConnectOnlyFallback, selectedWalletConnector, } = useInternalDynamicContext();
    const { addedWalletsIds } = useInternalUserWallets();
    const { initAuth } = useUserAuth({ authMethod: 'wallet' });
    const { generateSessionKey, shouldRegisterSessionKeysOnSignin } = useEmbeddedWalletSessionKeys({
        environmentId,
        projectSettings,
    });
    // If the user is not already logged it means that we only need to verify
    // We need this boolean to distinguish between logic for verify or linking.
    const verifyOnly = !user;
    const shouldFallbackToConnectOnly = enableConnectOnlyFallback && (verifyOnly || !multiWalletEnabled);
    const generateJWT = (walletConnector, walletProvider, getAddressOpts, publicWalletAddress, captchaToken, oauth, signedMessageOverride, messageToSignOverride) => __awaiter(void 0, void 0, void 0, function* () {
        const verifyArgs = yield getVerifyArgs({
            displaySiweStatement,
            environmentId,
            getAddressOpts,
            messageToSignOverride,
            publicWalletAddress,
            signedMessageOverride,
            siweStatement: getSiweStatement({ appName, siweStatement }),
            walletConnector,
            walletProvider,
        });
        if (shouldRegisterSessionKeysOnSignin() && verifyOnly) {
            const keypair = yield generateSessionKey();
            verifyArgs.sessionPublicKey = keypair.publicKey;
        }
        yield generateClientSessionKeys();
        let verifyResponse;
        if (!user) {
            verifyResponse = verifyWallet(environmentId, Object.assign(Object.assign({}, verifyArgs), { captchaToken,
                oauth }));
        }
        else {
            verifyResponse = linkWallet(environmentId, verifyArgs);
        }
        return { verifyArgs, verifyFunction: () => verifyResponse };
    });
    // Overrides the stored primary wallet id when the
    // user logs in for the first time.
    // Or when the user is linking an additional
    // account on the same wallet as the primary wallet.
    const updatePrimaryWallet = ({ walletConnector, verifiedCredentials, lastVerifiedCredentialId, }) => {
        const newSelectedCredentialWallet = verifiedCredentials.find((cred) => cred.id === lastVerifiedCredentialId && cred.format === 'blockchain');
        if (newSelectedCredentialWallet) {
            const currentPrimaryWallet = verifiedCredentials.find((a) => a.id === primaryWalletId);
            if (verifyOnly ||
                !primaryWallet ||
                (multiWalletWidgetState === 'awaiting_signature' &&
                    newSelectedCredentialWallet.walletName ===
                        (currentPrimaryWallet === null || currentPrimaryWallet === void 0 ? void 0 : currentPrimaryWallet.walletName)) ||
                ((currentPrimaryWallet === null || currentPrimaryWallet === void 0 ? void 0 : currentPrimaryWallet.chain) === 'flow' &&
                    walletConnector.connectedChain === 'FLOW')) {
                updatePrimaryWalletId(newSelectedCredentialWallet.id);
            }
        }
    };
    const handleWalletUsedError = (e) => {
        var _a;
        // This is a special case where the user is trying to link a wallet
        // and the wallet is already linked and we don't want to kill the session.
        setShowAuthFlow(true);
        pushView('wallet-used');
        setIsSingleWalletAccount(false);
        if (e.code === 'reassign_wallet_error') {
            if ((_a = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.sdk) === null || _a === void 0 ? void 0 : _a.preventOrphanedAccounts) {
                pushView('wallet-cannot-be-transferred');
            }
            setIsSingleWalletAccount(true);
        }
    };
    const handleDisconnectWallet = ({ walletConnector, endSession = true, }) => {
        resetConnectedWalletsInfo();
        if (endSession)
            walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.endSession();
    };
    const handleError = (e, walletConnector, address, oauth) => {
        var _a;
        // see: PhantomRedirect#signMessage
        if (e.message === 'ignore') {
            return;
        }
        // Emit failure if this wallet connector was currently selected for auth
        if (selectedWalletConnector &&
            selectedWalletConnector.key === walletConnector.key)
            dynamicEvents.emit('authFailure', {
                address,
                connectorName: walletConnector.name,
                option: walletConnector.name,
                type: 'wallet',
            }, { error: e });
        if (e instanceof EmbeddedWalletExistsError) {
            pushView('embedded-wallet-exists');
            setShowAuthFlow(true);
            return;
        }
        if (e instanceof WalletUsedError) {
            handleDisconnectWallet({ endSession: false, walletConnector });
            return handleWalletUsedError(e);
        }
        if (e instanceof MergeAccountsConfirmationError) {
            pushView('merge-user-accounts', Object.assign({}, e));
            setShowAuthFlow(true);
            return;
        }
        if (e instanceof ChainalysisError) {
            handleDisconnectWallet({ walletConnector });
            setDeniedAddress(address);
            pushView('chainalysis-blocked-wallet');
            return;
        }
        if (e instanceof GateBlockedError) {
            handleDisconnectWallet({ walletConnector });
            setDeniedAddress(address);
            pushView('gate-blocked-wallet');
            return;
        }
        if (e instanceof SandboxMaximumThresholdReachedError) {
            pushView('sandbox-maximum-threshold-reached');
            return;
        }
        if (e instanceof NoAccessError) {
            handleDisconnectWallet({ walletConnector });
            setDeniedAddress(address);
            // we need to set this value if it's magic in order to set proper icon
            if (isSocialWalletConnector(walletConnector)) {
                setDeniedOauthProvider(oauth === null || oauth === void 0 ? void 0 : oauth.provider);
            }
            pushView('no-access');
            return;
        }
        if (e instanceof AccountExistsError) {
            handleDisconnectWallet({ walletConnector });
            setExistentAccountData(e.errorPayload);
            pushView('account-exists');
            return;
        }
        const authMode = getAuthMode();
        if (connectedWallets.length && authMode === 'connect-only') {
            throw new DynamicError(e.message);
        }
        const userRejectedRequestError = (_a = e === null || e === void 0 ? void 0 : e.message) === null || _a === void 0 ? void 0 : _a.includes('User rejected the request');
        const fallbackToConnectOnly = shouldFallbackToConnectOnly && !userRejectedRequestError;
        if (fallbackToConnectOnly) {
            logger.warn('Verification failed, changing to connect-only');
            // verification failed for unknown reason, set authmode to connect-only and show wallet list
            setAuthMode('connect-only');
            pushView('wallet-list');
            return;
        }
        else {
            handleDisconnectWallet({ walletConnector });
            clearStackAndPushInitialView();
        }
        logger.error(e);
        if (debugError) {
            setError(`${e.message}\n ${e.stack}`);
        }
        else {
            setErrorMessage(e.code);
        }
    };
    return (_a) => __awaiter(void 0, [_a], void 0, function* ({ walletConnector, getAddressOpts, publicWalletAddress, captchaToken, oauth, signedMessageOverride, messageToSignOverride, }) {
        const walletProvider = getWalletProvider(walletConnector);
        dynamicEvents.emit('authInit', {
            address: publicWalletAddress,
            connectorName: walletConnector.name,
            option: walletConnector.name,
            type: 'wallet',
        });
        try {
            const { verifyFunction, verifyArgs } = yield generateJWT(walletConnector, walletProvider, getAddressOpts, publicWalletAddress, captchaToken, oauth, signedMessageOverride, messageToSignOverride);
            yield initAuth({
                isSignIn: verifyOnly,
                onError: (e) => {
                    handleError(e, walletConnector, publicWalletAddress, oauth);
                },
                onVerifySuccess: (user) => {
                    var _a;
                    if (!user) {
                        throw new DynamicError(USER_NOT_LOGGED_IN);
                    }
                    try {
                        (_a = events === null || events === void 0 ? void 0 : events.onSignedMessage) === null || _a === void 0 ? void 0 : _a.call(events, {
                            messageToSign: verifyArgs.messageToSign,
                            signedMessage: verifyArgs.signedMessage,
                        });
                    }
                    catch (_b) {
                        logger.warn('Error calling onSignedMessage callback');
                    }
                    StorageService.setItem(LAST_USED_WALLET, walletConnector.key);
                    setAuthMode('connect-and-sign');
                    updatePrimaryWallet({
                        lastVerifiedCredentialId: user.lastVerifiedCredentialId,
                        verifiedCredentials: user.verifiedCredentials,
                        walletConnector,
                    });
                    const walletId = user.lastVerifiedCredentialId;
                    if (walletId) {
                        addedWalletsIds.current.push(walletId);
                    }
                },
                options: {
                    address: publicWalletAddress,
                    connectorName: walletConnector.name,
                },
                skipDefaultErrorHandling: true,
                verifyFunction,
            });
        }
        catch (e) {
            handleError(e, walletConnector, publicWalletAddress, oauth);
        }
    });
};

export { useVerifyWallet };
