import type { FunAddress } from '@funkit/api-base';
import type { ApiCheckoutClientMetadata, ApiFunkitCheckoutActionParams, ApiFunkitCheckoutConfig } from '@funkit/utils';
import type { ReactNode } from 'react';
import type { Address } from 'viem';
import type { PaymentMethodInfo } from '../../domains/paymentMethods';
import type { CheckoutBlockedReason } from '../../modals/CheckoutModal/CheckoutBlockedReason';
import type { WithdrawalClient, WithdrawalTransaction } from '../../wallets/Wallet';
import type { FunkitCheckoutQuoteResult } from '../FunkitHistoryContext';
export type FunkitCheckoutActionParams = ApiFunkitCheckoutActionParams;
export interface TokenInfo {
    tokenAddress: Address;
    tokenChainId: string;
}
/**
 * Argument passed to a dynamic {@link FunkitCheckoutConfig.modalTitle} resolver.
 * Extends {@link TokenInfo} with the active dynamic routing id so titles can be
 * keyed by route/action — not just token address — which matters when two
 * routes share a target token (e.g. Lighter USDC perps vs spot both deposit
 * mainnet USDC).
 */
export interface ModalTitleContext extends TokenInfo {
    dynamicRoutingId?: string;
}
export interface DynamicTargetAssetCandidate extends TokenInfo {
    iconSrc: string;
    tokenSymbol: string;
    isDefault?: boolean;
    badgeText?: string;
    targetAssetMinAmount?: number;
    /**
     * Exchange rate of the target asset in terms of the finalized token.
     * Represents how many finalized tokens one unit of the target asset can be exchanged for.
     *
     * Example: If `targetAsset`/`finalizedToken` is USDT/hbUSDT and the rate is 1.01,
     * 1 USDT can be exchanged for 1.01 hbUSDT.
     */
    finalizedTokenRate?: number;
    dynamicRoutingId?: string;
    /**
     * Recipient to point the checkout at when this candidate is selected. Set when
     * candidates represent destination *accounts* that share a target token but
     * differ by recipient (e.g. Polymarket Predictions vs Perps); selecting one
     * routes funds to its address. Omit for plain token candidates (the recipient
     * is unchanged).
     */
    customRecipient?: Address;
}
/**
 * A token to offer adding to the user's wallet (EIP-747 `wallet_watchAsset`) on
 * the post-checkout success screen.
 *
 * Set this when the token the user ends up holding differs from the checkout's
 * destination token — e.g. a vault receipt token (Aave's aUSDT) minted by a
 * post-swap supply action, where the checkout's `toTokenAddress` is the
 * intermediate underlying (USDT), not the token the wallet should track.
 *
 * Purely a post-checkout UX affordance: nothing in quoting, routing, or amount
 * display reads this field, so setting it cannot perturb a checkout's quote.
 */
export interface AddToWalletToken extends TokenInfo {
    /** Symbol shown in the wallet prompt (e.g. "aUSDT"). */
    tokenSymbol: string;
    /** Token decimals. If omitted, the button reads `decimals()` on-chain. */
    decimals?: number;
    /** Optional token icon, passed to the wallet as `image`. */
    iconSrc?: string;
}
export declare enum FunCheckoutStartingStep {
    SOURCE_CHANGE = "source_change",
    CONFIRMATION = "confirmation",
    SELECT_ASSET = "select_asset",
    /**
     * Open directly on the Polymarket perps ⇄ predictions transfer step.
     * Requires {@link FunkitCheckoutConfig.polymarketPerpsTransfer} handles
     * (set by `createPolymarketDepositConfig`) — without them the step renders
     * but cannot transfer.
     */
    PERPS_TRANSFER = "perps_transfer"
}
/** Token a Polymarket account can be topped up with. */
export type PolymarketTopupToken = 'pUSD';
/**
 * A Polymarket account in the transfer step. Both accounts share the same shape
 * so each direction is symmetrical and integrator-owned.
 */
export interface PolymarketTransferAccount {
    /** Account address (the transfer target when funds move *into* it). */
    address: Address;
    /** Minimum amount (USD) to top this account up with `token` (0 = none). */
    getMinTopupAmount: (token: PolymarketTopupToken) => number;
    /**
     * Transfers funds *from* this account to `toAddress`. Implemented by the
     * integrator (keeps their perps API auth in-house); the SDK invokes the
     * source account's transfer when the user confirms. `amountUsd` is the exact
     * string the user entered (validated numeric, ≤6 decimals) — never a parsed
     * number — so no float precision is lost before the integrator scales it.
     */
    transfer: (params: {
        toAddress: Address;
        amountUsd: string;
    }) => Promise<void>;
    /**
     * Fetches this account's live balance (USD). The transfer step polls this so
     * the displayed balances reconcile with the real on-chain / perps-API state
     * after a transfer (optimistic updates alone go stale). Integrator-owned.
     */
    getBalanceUsd: () => Promise<number>;
}
/** The two accounts the perps transfer step moves funds between. */
export interface PolymarketPerpsTransferHandles {
    predictions: PolymarketTransferAccount;
    perps: PolymarketTransferAccount;
}
export interface FunkitCheckoutConfig extends Omit<ApiFunkitCheckoutConfig, 'generateActionsParams' | 'customRecipient' | 'modalTitle' | 'iconSrc' | 'modalTitleMeta'> {
    /** List of contract action params **/
    generateActionsParams?: (targetAssetAmount: number, config?: {
        targetAsset: Address;
        targetChain: string;
    }) => Promise<FunkitCheckoutActionParams[]>;
    /** Custom recipient address of the checkout. If specified, a different checkout flow will be executed. It is not recommended to set this unless the Fun.xyz team advises it. **/
    customRecipient?: FunAddress;
    /** ****************************************
     * Checkout ModalUI-related configurations *
     *******************************************/
    /** Title to show in the checkout modal. Defaults to "Checkout".
     * The resolver receives the target token plus the active `dynamicRoutingId`,
     * so titles can disambiguate routes that share a target token. **/
    modalTitle?: string | ((asset: ModalTitleContext) => string);
    /** Additional information to show in the title of the checkout modal. Blank by default **/
    modalTitleMeta?: string;
    /**
     * Integrator-provided, display-only yield metadata for the destination
     * (e.g. an Aave/Felix/Benqi supply). The SDK never computes these — the
     * integrator resolves them from their own data source and passes a snapshot
     * at checkout-init time. When present, the confirmation screen renders it as
     * Supply APY / Collateralization rows (`DestinationYieldRows`). Omitted
     * segments are simply not rendered.
     */
    destinationYieldInfo?: {
        /** Supply APY as a display string without the % sign (e.g. "2.79"). */
        supplyApy?: string;
        /** Whether the supply is/will be enabled as collateral for the user. */
        collateralizationEnabled?: boolean;
    };
    /** Icon to show in the checkout modal (50px x 50px). If not specified, no icon will be shown. **/
    iconSrc?: null | string;
    /** Title of the item being checked out. e.g. Staked Ether, XYZ Option, Solar Bond ABC **/
    checkoutItemTitle: string;
    /** amount of source token. it is not baseUnit **/
    withdrawalSourceTokenBalance?: () => string | number;
    /** @deprecated isDefiMode has been removed. This field is ignored. */
    isDefiMode?: boolean;
    /** The step at which the checkout process should start */
    startingStep?: FunCheckoutStartingStep;
    /** Symbol of the source token. Required if startingStep is set to FunCheckoutStartingStep.CONFIRMATION. */
    sourceTokenSymbol?: string;
    /** ID of the source chain. Required if startingStep is set to FunCheckoutStartingStep.CONFIRMATION. */
    sourceChain?: string;
    /** Address of the source token on the source chain. Required if startingStep is set to FunCheckoutStartingStep.CONFIRMATION. */
    sourceTokenAddress?: Address;
    /** Address list of the tokens that cannot be used as source. e.g. tokens for staking vault */
    disabledSourceTokens?: TokenInfo[];
    /** *****************************
     * Miscellaneous configurations *
     ********************************/
    /** a list of candidate assets to be chosen dynamically */
    dynamicTargetAssetCandidates?: DynamicTargetAssetCandidate[];
    /**
     * Minimal USD needed to deposit. Receives the active `dynamicRoutingId` (like
     * {@link modalTitle}) so the minimum can vary by route when two routes share a
     * target token (e.g. Polymarket predictions vs perps).
     */
    getMinDepositUSD?: (asset: ModalTitleContext) => number;
    /** For Checkout with Custom Action, QRCode needs special action type
     * to specify the onchain action to execute after deposit */
    qrcodeActionType?: string;
    /**
     * Polymarket-specific handles for the perps ⇄ predictions transfer step. Set
     * by `createPolymarketDepositConfig` and read by the perps transfer step.
     * Lets Polymarket keep their perps API auth in-house (they implement the
     * withdrawal) instead of handing the SDK an API key.
     */
    polymarketPerpsTransfer?: PolymarketPerpsTransferHandles;
    /** set this if you want enable vault like deposit*/
    finalizedToken?: DynamicTargetAssetCandidate;
    /**
     * For dynamic routing, the id of the dynamic route to use
     */
    dynamicRoutingId?: string;
    /**
     * Force a specific bridge provider for the checkout quote.
     * Set via dynamic routing rules.
     */
    bridgeOverride?: 'across' | 'relay';
    /**
     * Token to offer adding to the user's wallet on the post-checkout success
     * screen via EIP-747 `wallet_watchAsset`. Set when the held token differs
     * from the checkout's destination token (e.g. an Aave aUSDT receipt). See
     * {@link AddToWalletToken}.
     */
    addToWalletToken?: AddToWalletToken;
}
export interface WithdrawalConfigBase {
    /** Title to show in the checkout modal. Defaults to "Checkout" **/
    modalTitle: string;
    /** Additional information to show in the title of the checkout modal. Blank by default **/
    modalTitleMeta?: string;
    /** Icon to show in the checkout modal (50px x 50px). If not specified, no icon will be shown. **/
    iconSrc?: null | string;
    sourceTokenSymbol: string;
    /** source chain id to withdraw **/
    sourceChainId: string;
    /** source token id to withdraw **/
    sourceTokenAddress: Address;
    /** Disable connected option for email login user */
    disableConnectedWallet?: boolean;
    /** Default token to select in the receive token dropdown. Falls back to sourceTokenSymbol if not set. */
    defaultReceiveToken?: string;
    /** minimal USD needed to withdraw */
    getMinWithdrawalUSD?: (asset: TokenInfo) => number;
    /**
     * Returns the minimum withdrawal amount in token units for the given symbol.
     * Used when the source token can vary (e.g. Lighter Secure withdrawal).
     */
    getMinWithdrawalAmount?: (symbol: string) => number;
    /**
     * Returns the current withdrawable balance for the source token.
     * Called on every render — use a ref-backed stable callback so the value
     * stays live without triggering unnecessary re-renders.
     */
    withdrawalSourceTokenBalance?: () => string | number;
}
export interface WalletWithdrawalConfig extends WithdrawalConfigBase {
    /** Wallet instance used to execute the quote */
    wallet: WithdrawalClient;
    /**
     * Optional async hook that runs **before** the SDK executes the wallet-based
     * withdrawal quote. Return any transactions that must execute as part of the
     * withdrawal flow *prior* to the SDK's withdrawal transaction (e.g. an
     * `approve` and a custom-collateral `unwrap` that produces the source token).
     *
     * The SDK atomically prepends the returned array to the withdrawal txn(s)
     * via the integrator's `wallet.sendTransactions` primitive, so the
     * approve/unwrap and the withdrawal land in a single user signature.
     *
     * Return `[]` if no extra transactions are required — the hook is then
     * purely a side-effect / preflight step.
     *
     * Throw to abort the withdrawal — the thrown error message is surfaced to
     * the user in the standard error UI.
     *
     * Mutually exclusive with {@link CustomWithdrawalConfig['withdrawCallback']}
     * by virtue of living on a different config variant.
     */
    preWithdrawalAction?: (param: WithdrawalParam) => Promise<WithdrawalTransaction[]>;
}
export interface CustomWithdrawalConfig extends WithdrawalConfigBase {
    /**
     * @returns Optionally return a transaction hash string. When provided, the
     *   success screen can display and link to the transaction.
     */
    withdrawCallback: (param: WithdrawalParam) => Promise<undefined | string>;
}
export interface WithdrawalParam {
    quoteId: string;
    funQuote: unknown;
    targetAssetAddress: Address;
    targetChainId: number;
    destinationAddress: Address;
    /** Lighter asset index for quoteless Secure withdrawal (avoids overloading targetChainId). */
    lighterAssetIndex?: number;
    /** User-entered amount in token units for quoteless flows (avoids overloading quoteId). */
    userInputAmount?: string;
    /**
     * USD value of the withdrawal as computed by the modal (token amount × live
     * spot price). Provided so quoteless flows (e.g. Lighter Secure) don't need
     * a separate price round-trip to compute `estTotalUsd` for tracking.
     */
    withdrawalUSD?: string;
}
/**
 * A single entry in a {@link MultiMethodWithdrawalConfig}.
 *
 * Each option represents a distinct withdrawal method (e.g. "Fast" vs "Secure")
 * that the user can pick from a selection screen before entering amounts.
 */
export interface WithdrawalMethodOption {
    /** Stable id used for tracking/analytics. */
    id: string;
    /** Primary label (e.g. "Fast"). */
    keyText: string;
    /** Optional subtitle (e.g. "USDC Perps only · Multiple chains · Instant"). */
    subtitleText?: string;
    /** Optional leading icon. */
    icon?: ReactNode;
    /** Optional trailing badge/icon rendered to the right of the label. */
    valueIcon?: ReactNode;
    /**
     * The actual withdrawal config that drives the flow once the user selects
     * this option. Must be a single concrete (non-multi) config.
     */
    config: WalletWithdrawalConfig | CustomWithdrawalConfig;
}
/**
 * Withdrawal config that presents the user with a selection screen before
 * entering the standard withdrawal flow. Once a method is picked, the modal
 * delegates to that method's inner config.
 */
export interface MultiMethodWithdrawalConfig {
    /** Title shown in the modal header. */
    modalTitle: string;
    /** Optional meta under the title. */
    modalTitleMeta?: string;
    /** Optional section label above the options list (e.g. "Crypto"). */
    sectionTitle?: string;
    /** The methods the user can choose between. Order is preserved in the UI. */
    methods: WithdrawalMethodOption[];
    disableConnectedWallet?: boolean;
}
export type FunkitWithdrawalConfig = WalletWithdrawalConfig | CustomWithdrawalConfig | MultiMethodWithdrawalConfig;
export interface FunkitCheckoutValidationResult {
    isValid: boolean;
    message: string;
}
export interface FunkitCheckoutOnCloseResult {
    isNewDeposit: boolean;
    /** True if the modal was soft-hidden (state preserved) instead of hard-closed */
    isSoftHidden?: boolean;
}
/**
 * Conflict resolution options when beginCheckout is called while a soft-hidden checkout exists
 */
export interface CheckoutConflictResolution {
    /** The ID of the hidden checkout */
    hiddenCheckoutId: string;
    /** Resume the hidden checkout (reshow the modal without starting new checkout) */
    resume: () => void;
    /** Replace the hidden checkout with a new one (discard hidden state, proceed with new checkout) */
    replace: () => void;
}
export type FunkitCheckoutResult = {
    type: 'error' | 'success';
    message: string;
    metadata: object | Error;
};
export interface UseFunkitCheckoutProps {
    /** @optional the checkout config object **/
    config?: FunkitCheckoutConfig;
    /** @optional fires when the checkout modal is opened **/
    onOpen?: () => void;
    /** @optional fires when the checkout modal is closed **/
    onClose?: (result: FunkitCheckoutOnCloseResult) => void;
    /** @optional fires when checkout config is done validating **/
    onValidation?: (result: FunkitCheckoutValidationResult) => void;
    /** @optional fires when a checkout quote is received **/
    onEstimation?: (result: FunkitCheckoutQuoteResult) => void;
    /** @optional fires when a checkout is confirmed with the funkit server. Returns the newly created checkoutId. **/
    onConfirmation?: (checkoutId: string) => void;
    /** @optional fires if the checkout fails at any point **/
    onError?: (result: FunkitCheckoutResult) => void;
    /** @optional fires after the checkout steps are completed **/
    onSuccess?: (result: FunkitCheckoutResult) => void;
    /**
     * @optional
     * fires if the checkout requires an active wallet connection. If not specified, defaults to funkit wallet connection.
     * Call the provided `onLoginFinished()` callback once login is completed to resume the checkout flow (and unhide the soft-hidden modal).
     * It is strongly recommended to call `onLoginFinished()` after login is completed. If not called, the checkout modal may remain hidden.
     */
    onLoginRequired?: ({ onLoginFinished, }: {
        onLoginFinished?: () => void;
    }) => void;
    /** @optional fires when a withdrawal is confirmed with the funkit server. Returns the newly created withdrawalId. **/
    onWithdrawalConfirmation?: (withdrawalId: string) => void;
    /** @optional fires when checkout is blocked (e.g. geo-restriction, security hold, or missing wallet connection). **/
    onCheckoutBlocked?: (params: {
        blockedReason: CheckoutBlockedReason;
    }) => void;
    /** @optional fires if the withdrawal fails at any point **/
    onWithdrawalError?: (result: FunkitCheckoutResult) => void;
}
/** Ensures that config is defined */
export interface UseFunkitCheckoutPropsWithFullConfig extends UseFunkitCheckoutProps {
    config: FunkitCheckoutConfig;
}
/**
 * Checkout Item for frontend use
 */
export interface FunkitActiveCheckoutItem extends Omit<ApiCheckoutClientMetadata, 'selectedPaymentMethodInfo' | 'initSettings'> {
    /** The deposit address provided by server after the checkout is confirmed. If `null`, it is not confirmed yet. **/
    depositAddress: null | Address;
    /** Final settings the checkout was init-ed with **/
    initSettings: UseFunkitCheckoutPropsWithFullConfig;
    /** User's selected payment method information */
    selectedPaymentMethodInfo: PaymentMethodInfo | null;
    /** User's choice of source asset to fund the checkout operation **/
    selectedSourceAssetInfo: {
        address: Address | null;
        symbol: string | null;
        chainId: string;
        iconSrc: string | null;
    };
    /** Time of completion of the active checkout item. For frontend use only. **/
    completedTimestampMs: number | null;
    sourceAssetAmount: string | null;
    /** In EXACT_IN mode, the fiat value the user entered on InputAmount.
     *  Stored alongside targetAssetAmount so the confirmation screen can display
     *  the same dollar value without recomputing from the token amount. */
    inputFiatAmount: number | null;
    /** Canonical token amount in base units (e.g. 328257705848429095n).
     *  Avoids precision loss from bigint→number round-trips for EXACT_IN quotes. */
    inputTokenAmountBaseUnits: bigint | null;
}
export interface FunkitActiveWithdrawalItem {
    /** Unique identifier for frontend use only. */
    id: string;
    /** Final settings the withdrawal was init-ed with **/
    initSettings: Partial<UseFunkitCheckoutPropsWithFullConfig>;
    withdrawalSourceTokenBalance: () => string | number;
}
