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;
import type { DynamicTargetAssetCandidate, TokenInfo } from '@funkit/connect-core';
export type { DynamicTargetAssetCandidate, TokenInfo, } from '@funkit/connect-core';
/**
 * 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;
}
/**
 * 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;
    };
    /**
     * Integrator-provided health-factor resolver for a lending supply (e.g. Aave).
     * The SDK never computes health factor — the integrator owns the math (run
     * against live position data with the protocol's own library, e.g.
     * `@aave/math-utils`) so it matches the protocol app exactly. The SDK calls
     * this at the confirmation step with the live supply amount (the target
     * asset, human units) and renders the result as a Health factor (before →
     * after) row. Return `null` when the position data isn't ready, or for an
     * infinite/no-debt health factor return `"-1"` (rendered as ∞).
     */
    resolveHealthFactor?: (targetAssetHumanAmount: string) => {
        before: string | null;
        after: string | null;
    } | null;
    /** 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;
    /**
     * 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;
    /**
     * Maximum USD value allowed for a single withdrawal. Amounts above this block
     * the CTA (which switches to "Max amount exceeded"). Omit for no upper bound.
     * Mirrors {@link getMinWithdrawalUSD}.
     */
    getMaxWithdrawalUSD?: (asset: TokenInfo) => 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;
    /**
     * Optional async hook fired when the user commits to the withdrawal — after
     * the withdraw CTA, but before any nonce fetch, wallet signature, or tx
     * submission. Awaited, so async work completes before signing begins.
     *
     * Throw to abort: the error message is surfaced to the user verbatim and no
     * nonce is consumed. Runs on every withdrawal method, before
     * {@link WalletWithdrawalConfig.preWithdrawalAction}.
     */
    onBeforeSign?: () => Promise<void> | void;
}
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[]>;
    /**
     * Token that Swapped accepts for fiat withdrawal. When set and differs from
     * {@link WithdrawalConfigBase.sourceTokenAddress}, the Swapped controller
     * fetches a Relay quote to swap the source token into this token before
     * sending to Swapped's deposit address.
     */
    swappedTargetTokenAddress?: Address;
    /**
     * Chain ID for the Swapped target token. Defaults to
     * {@link WithdrawalConfigBase.sourceChainId} when omitted.
     */
    swappedTargetChainId?: string;
    /**
     * Symbol of the Swapped target token (e.g. 'USDC'). Recorded against the
     * on-chain movement, which is denominated in the target — not the source —
     * token. Defaults to {@link WithdrawalConfigBase.sourceTokenSymbol}.
     */
    swappedTargetTokenSymbol?: string;
}
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>;
}
/** Lighter L2 route type: 0 = perps (USDC collateral), 1 = spot. */
export type LighterRouteType = 0 | 1;
/**
 * Lighter-specific data for quoteless Secure withdrawal. `assetIndex` selects
 * the L2 asset (avoids overloading targetChainId); `routeType` disambiguates
 * USDC, whose perps and spot balances share asset index 3.
 */
export interface LighterWithdrawalCustomerData {
    customerName: 'lighter';
    assetIndex: number;
    routeType: LighterRouteType;
}
/**
 * Customer-specific data threaded through withdrawal callbacks, discriminated
 * by `customerName` so future customers extend the union instead of adding
 * top-level params.
 */
export type WithdrawalCustomerData = LighterWithdrawalCustomerData;
export interface WithdrawalParam {
    quoteId: string;
    funQuote: unknown;
    targetAssetAddress: Address;
    targetChainId: number;
    destinationAddress: Address;
    /** Customer-specific data for quoteless flows (e.g. Lighter Secure). */
    customerData?: WithdrawalCustomerData;
    /** 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;
        /** Source token decimals, when known — lets later screens reconstruct
         *  base-unit amounts. */
        decimals?: number;
    };
    /** 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;
}
