import { KaminoMarket, KaminoObligation, KaminoReserve, ObligationStats, Position } from '../classes';
import { SwapIxsProvider, SwapQuoteProvider } from '../leverage';
import { KlendAccountsResult } from '../utils';
import { Account, Address, Instruction, Option, Slot, TransactionSigner } from '@solana/kit';
import Decimal from 'decimal.js';
import { AddressLookupTable } from '@solana-program/address-lookup-table';
/**
 * Which debt token to flash borrow for a swap-debt operation.
 *
 * - `targetDebt`: flash borrow target debt → swap target → source → repay source → borrow target → flash repay.
 * - `sourceDebt`: flash borrow source debt → repay source → borrow target → swap target → source → flash repay.
 */
export type SwapDebtFlashBorrowToken = 'sourceDebt' | 'targetDebt';
export interface SwapDebtIxsInputs<QuoteResponse> {
    /**
     * Amount of source debt to be reduced (i.e. replaced with target debt), in source-debt token units.
     * The obligation's source debt will be repaid by this amount.
     */
    sourceDebtSwapAmount: Decimal;
    /**
     * If true, the full outstanding source debt will be repaid (regardless of `sourceDebtSwapAmount`).
     */
    isClosingSourceDebt: boolean;
    sourceDebtReserveAddress: Address;
    targetDebtReserveAddress: Address;
    flashBorrowToken: SwapDebtFlashBorrowToken;
    /**
     * Elevation group the obligation should end up with after the swap.
     *
     * Leave `undefined` to use the default selection: an in-place vanilla/lending swap keeps the obligation's current
     * group, and a Multiply/Leverage migration into a NEW target obligation auto-selects the highest-LTV common
     * elevation group for the (collateral, new debt) pair (or none). Pass a number — including `0` (no emode) — to
     * request exactly that group.
     *
     * NOTE: for a Multiply/Leverage migration that grows an ALREADY-EXISTING target obligation, the target's
     * elevation group is never changed; passing a group that differs from its current one is rejected rather than
     * silently ignored.
     */
    newElevationGroup?: number;
    market: KaminoMarket;
    owner: TransactionSigner;
    obligation: KaminoObligation;
    referrer: Option<Address>;
    currentSlot: Slot;
    /**
     * Slippage percentage for the external swap (e.g. 0.5 for 0.5%). Used to size the flash loan above the strict
     * minimum so that the swap does not fail.
     */
    slippagePct: Decimal;
    budgetAndPriorityFeeIxs?: Instruction[];
    scopeRefreshIx: Instruction[];
    useV2Ixs: boolean;
    quoter: SwapQuoteProvider<QuoteResponse>;
    swapper: SwapIxsProvider<QuoteResponse>;
    logger?: (msg: string, ...extra: unknown[]) => void;
}
/**
 * One built route returned by {@link getSwapDebtIxs}. `getSwapDebtIxs` returns an array of these — one per route the
 * `swapper` produced — and does NOT pre-validate them against the downstream repay/flash-repay amount (see the
 * `getSwapDebtIxs` doc). The caller picks a route via its own simulation/filtering.
 */
export interface SwapDebtIxsOutputs<QuoteResponse> {
    ixs: Instruction[];
    lookupTables: Account<AddressLookupTable>[];
    useV2Ixs: boolean;
    simulationDetails: {
        flashLoan: {
            flashBorrowReserveMint: Address;
            flashBorrowedAmount: Decimal;
            flashRepaidAmount: Decimal;
        };
        externalSwap: {
            swapInMint: Address;
            swapOutMint: Address;
            swapInAmount: Decimal;
            swapOutAmount: Decimal;
            quoteResponse?: QuoteResponse;
        };
        /**
         * For a debt-seeded obligation (Multiply or Leverage) migrated by swap-debt, the address of the target
         * obligation the position is moved into — the same obligation type, seeded with the new debt. It may be a
         * brand-new obligation or a pre-existing one being grown by a partial swap. Undefined for the in-place
         * vanilla/lending swap flows.
         */
        newObligationAddress?: Address;
        /**
         * For a Multiply/Leverage migration, the collateral amount (in target/collateral token units, not lamports)
         * moved from the old obligation into the target. Equals the whole collateral for a full swap, or the
         * proportional slice for a partial swap. Undefined for the in-place vanilla/lending swap flows.
         */
        migratedCollateralAmount?: Decimal;
        /**
         * For a Multiply/Leverage migration, the old debt amount (in source-debt token units, not lamports) repaid on
         * the old obligation. Equals the full outstanding (plus interest buffer) for a full swap, or `sourceDebtSwapAmount`
         * for a partial swap. Undefined for the in-place vanilla/lending swap flows.
         */
        repaidOldDebtAmount?: Decimal;
    };
}
/**
 * Constructs instructions needed to partially/fully swap the given source debt for some other debt.
 *
 * Route contract — IMPORTANT for callers: this returns ONE built `SwapDebtIxsOutputs` per route the `swapper`
 * returns, in the swapper's order, with a complete transaction assembled around each. The routes are NOT
 * pre-validated against the downstream repay / flash-repay requirement: the SDK does not drop or re-order routes by
 * predicted output (the swapper may legitimately return constrained routes alongside its best one). Each route's
 * own swap instruction carries a `min_out`, and the downstream repay/flash-repay reverts on-chain if a route
 * under-delivers — that is the enforcement layer. Callers are expected to choose between the returned routes by
 * running their own simulation/filtering (e.g. simulate each and pick the first that lands, or rank by simulated
 * output) rather than assuming `result[0]` is viable.
 */
export declare function getSwapDebtIxs<QuoteResponse>(inputs: SwapDebtIxsInputs<QuoteResponse>): Promise<Array<SwapDebtIxsOutputs<QuoteResponse>>>;
/**
 * Inputs for {@link getSwapDebtKlendAccounts}: the routing/sizing inputs of {@link getSwapDebtIxs} minus the
 * quoter/swapper (and logger), since the klend account footprint is discovered without an external swap.
 */
export type SwapDebtKlendAccountsInputs = Omit<SwapDebtIxsInputs<unknown>, 'quoter' | 'swapper' | 'logger'>;
/**
 * Light helper: returns the exact, final set of klend accounts (and program ids) a {@link getSwapDebtIxs} call with
 * the same inputs would consume, plus their count, WITHOUT calling the quoter/swapper. The operation computes this
 * same set from its klend ixs before quoting and the set is invariant to the swap amounts, so the count is accurate
 * and final — the FE can use it to know how many accounts remain for the external swap within the tx account limit.
 */
export declare function getSwapDebtKlendAccounts(inputs: SwapDebtKlendAccountsInputs): Promise<KlendAccountsResult>;
/**
 * Single source of truth for the old-debt repay sizing, shared by the debt-swap flows and the FE preview so the
 * previewed and executed repay amounts always agree. Takes explicit fields (rather than the internal args/context)
 * so the preview, which has no full {@link SwapDebtContext}, can call it directly.
 *
 * - Full close (`isClosingSourceDebt`): the full outstanding source debt, grown by estimated interest accrual plus a
 *   small safety buffer so the amount covers the actual debt that exists at the moment of the on-chain repay.
 * - Partial: exactly `sourceDebtSwapAmount` (in lamports). The on-chain repay is capped at the outstanding amount,
 *   and the caller is validated against the outstanding debt in `extractArgsAndContext`.
 */
export declare function resolveSourceDebtRepayLamports(params: {
    market: KaminoMarket;
    obligation: KaminoObligation;
    sourceDebtReserve: KaminoReserve;
    isClosingSourceDebt: boolean;
    sourceDebtSwapAmount: Decimal;
    currentSlot: Slot;
}): Decimal;
export type MultiplyMigrationSizing = {
    /** Old-debt repay (lamports). Full close: outstanding + interest + buffer; partial: `sourceDebtSwapAmount`. */
    oldDebtRepayLamports: Decimal;
    /** Proportional fraction of the position being moved: `f = oldDebtRepay / totalOldDebt`, clamped to [0, 1]. */
    f: Decimal;
    /** Collateral to move (liquidity lamports) = `floor(f * collateralSnapshot)`. Full close: `floor(snapshot)`. */
    collToMoveLamports: Decimal;
    /** Whether the migration empties the old obligation (full close). */
    isFullMigration: boolean;
};
/**
 * Sizes a multiply/leverage debt-swap migration. The collateral moved is proportional to the debt repaid so the
 * position's LTV is preserved on both sides (the moved slice and the remaining old obligation keep ~the original
 * LTV). A full swap (`isClosingSourceDebt`) degenerates to `f = 1` and moves the whole (floored) collateral
 * snapshot, reproducing the pre-partial full-migration behaviour exactly. Shared by the builder and the FE preview
 * so the previewed and executed sizing match.
 *
 * `collToMoveLamports` is floored so that we re-deposit a whole, conservative number of liquidity lamports into the
 * target — the amount we re-deposit is therefore always ≤ what the old-obligation withdraw makes available (the
 * on-chain withdraw rounds the liquidity→cToken conversion UP, see the builder), so there is never a "deposit more
 * than available" failure. Note this floor does NOT make the old obligation strictly healthier: the on-chain withdraw
 * removes up to ~1 cToken more than `floor(f · snapshot)` and the repay is `ceil`-rounded, so the old obligation's
 * post-op LTV deviates from the exact proportional target by sub-unit dust in either direction — negligible for
 * health, and the explicit old-obligation LTV check covers the result regardless. `f` is clamped to 1 defensively
 * (the partial repay is already capped against the outstanding debt upstream, but the `ceil` in the repay sizing
 * could otherwise push the ratio a hair above 1).
 */
export declare function computeMultiplyMigrationSizing(params: {
    oldDebtRepayLamports: Decimal;
    totalOldDebtLamports: Decimal;
    collateralSnapshotLamports: Decimal;
    isClosingSourceDebt: boolean;
}): MultiplyMigrationSizing;
/**
 * Pure helper exposed for unit testing: computes the flash-repay amount (in lamports) for a flash-borrow of
 * `flashBorrowLamports` on `reserve`. Ceils the result so the resulting amount is always an integer number of
 * lamports that is at least the (potentially fractional) fee-included sum. The borrow ix later uses `.toFixed(0)`
 * which would otherwise round half-to-up and could under-borrow by 1 lamport, causing the flash repay to fail.
 */
export declare function computeFlashRepayLamports(reserve: KaminoReserve, flashBorrowLamports: Decimal, referralFeeBps: number, hasReferrer: boolean): Decimal;
export interface SwapDebtObligationsPreviewInputs {
    market: KaminoMarket;
    /** The OLD Multiply/Leverage obligation being (partially) migrated, already loaded. */
    obligation: KaminoObligation;
    sourceDebtReserveAddress: Address;
    targetDebtReserveAddress: Address;
    /** Amount of source debt to repay/swap, in source-debt token units. Ignored when `isClosingSourceDebt`. */
    sourceDebtSwapAmount: Decimal;
    isClosingSourceDebt: boolean;
    /**
     * Which debt the execution will flash-borrow — MUST match the `flashBorrowToken` passed to `getSwapDebtIxs`. It
     * changes the new-debt amount through flash fees ('targetDebt' adds the target reserve's flash fee, 'sourceDebt'
     * the source reserve's), so the preview projects the matching target debt/LTV instead of an unfee'd estimate.
     */
    flashBorrowToken: SwapDebtFlashBorrowToken;
    /**
     * The elevation group the target should end up in — MUST match the `newElevationGroup` passed to `getSwapDebtIxs`,
     * so the preview projects the target at the same group execution will request. `undefined` = default selection (a
     * NEW target auto-picks the best common group, an EXISTING target keeps its current one), a number (including 0 =
     * no emode) = exactly that group. Omitting this while execution passes 0 would make the preview model a healthier
     * emode target than the transaction produces.
     */
    newElevationGroup?: number;
    slot: Slot;
    referrer: Option<Address>;
    /**
     * Slippage percentage for the external swap (e.g. 0.5 for 0.5%). Kept for parity with the execution inputs; the
     * preview's new-debt amount is an oracle-price estimate (see `moved.newDebtBorrowedLamports`), so it does not bias
     * the estimate by slippage.
     */
    slippagePct: Decimal;
}
export interface SwapDebtObligationPreviewSide {
    stats: ObligationStats;
    deposits: Map<Address, Position>;
    borrows: Map<Address, Position>;
}
export interface SwapDebtObligationsPreview {
    /** The OLD obligation after the (partial) repay+withdraw. `closed` when a full swap empties it. */
    old: SwapDebtObligationPreviewSide & {
        closed: boolean;
    };
    /** The TARGET obligation after the deposit+borrow. `isNew` when it does not exist on-chain yet. */
    new: SwapDebtObligationPreviewSide & {
        isNew: boolean;
        address: Address;
    };
    /**
     * The amounts the swap moves, in lamports. `oldDebtRepaidLamports` is exact (the same sizing the builder uses).
     * `collateralLamports` is the collateral the TARGET obligation actually receives — the redeem-drift-haircut deposit
     * on a full migration, the bare slice on a partial — matching the builder's deposit (the old obligation's withdraw
     * is sized separately/buffered). `newDebtBorrowedLamports` is an oracle-price estimate of the new borrow — the
     * executed amount differs by the live swap quote + slippage.
     */
    moved: {
        collateralLamports: Decimal;
        oldDebtRepaidLamports: Decimal;
        newDebtBorrowedLamports: Decimal;
    };
}
/**
 * Preview what BOTH obligations look like after a Multiply/Leverage debt swap, without building or sending a
 * transaction — useful for a UI that wants to show the projected position before the user signs.
 *
 * It shares the builder's planning core ({@link planMultiplyMigration}) for target selection, elevation group and
 * collateral sizing, so the projection cannot drift from what {@link getSwapDebtIxs} executes — provided the caller
 * passes the SAME `newElevationGroup` and `flashBorrowToken`. The OLD obligation is simulated through a
 * `repayAndWithdraw` of the proportional slice (marked `closed` for a full swap, which empties it). The TARGET is
 * simulated through a `depositAndBorrow` at its resulting elevation group (its current group when it already exists,
 * the requested/auto-selected group when new). The new debt is estimated from oracle prices, includes the chosen
 * flash side's flash fee and the origination fee so the projected LTV lines up with on-chain — the executed borrow
 * still differs by the live swap quote + slippage.
 */
export declare function getSwapDebtObligationsPreview(inputs: SwapDebtObligationsPreviewInputs): Promise<SwapDebtObligationsPreview>;
//# sourceMappingURL=swap_debt_operations.d.ts.map