package com.r35157.libs.jupiter.perps;

import com.r35157.libs.jupiter.JupiterTransactionOutcomeException;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Set;

/**
 * Service for reading Jupiter Perps data and executing complete position
 * operations for its configured wallet.
 *
 * <p>The service constructs and submits Jupiter transactions, while its
 * configured wallet is responsible for signing them. Position operations
 * return normally only after independent Solana {@code CONFIRMED} success.</p>
 */
public interface JupiterPerpsService extends NenjimComponent {
    /**
     * Reads a Jupiter Perps position from a known position account.
     *
     * <p>The supplied account must be the Solana account that stores the Jupiter Perps
     * position state. It is not the wallet address, token account, custody account, pool
     * account, or position request account.</p>
     *
     * @param positionAccount the Solana account address of the Jupiter Perps position
     * @return the decoded Jupiter Perps position
     * @throws IOException if the position account could not be fetched or decoded
     * @throws InterruptedException if the calling thread is interrupted while fetching
     *                              the position account
     */
    @Nullable JupiterPerpsPosition getPosition(@NotNull ΩJupiterPerpsPositionAccountΩ positionAccount)
            throws IOException, InterruptedException;

    /**
     * Finds open Jupiter Perps positions owned by a wallet.
     *
     * <p>This method returns decoded Jupiter Perps position objects. It does not return
     * raw Solana accounts or account ids.</p>
     *
     * @param owner the wallet address that owns the Jupiter Perps positions
     * @return the open Jupiter Perps positions owned by the wallet
     * @throws IOException if the position accounts could not be fetched or decoded
     * @throws InterruptedException if the calling thread is interrupted while fetching positions
     */
    @NotNull Set<JupiterPerpsPosition> getOpenPositions(@NotNull ΩSolanaWalletIdΩ owner)
            throws IOException, InterruptedException;

    /**
     * Opens or increases a Jupiter Perps position.
     *
     * <p>The service constructs the transaction, asks its configured wallet
     * to sign it, submits it to Jupiter, and independently awaits Solana
     * {@code CONFIRMED} success. A timeout or communication error after
     * submission leaves the on-chain outcome unknown and must not cause an
     * automatic resubmission.</p>
     *
     * @param tradedTokenMint the mint address of the asset being traded
     * @param direction whether the position is long or short
     * @param inputTokenAmount the amount of USDC to supply as collateral
     * @param sizeUsdDelta the requested increase in position size, denominated in USD
     * @param maxSlippageBps the maximum accepted slippage, in basis points
     * @return the independently confirmed Solana transaction signature
     * @throws IllegalArgumentException if an amount, mint, or slippage value is invalid
     * @throws IOException if the transaction cannot be constructed, signed,
     *                     submitted, or confirmed; after submission the
     *                     on-chain outcome can be unknown
     * @throws JupiterTransactionOutcomeException if the submitted transaction
     *         definitively fails on-chain or confirmation times out with an
     *         unknown outcome
     * @throws InterruptedException if the calling thread is interrupted;
     *                              interruption propagates directly
     */
    @NotNull
    ΩSolanaTransactionSignatureΩ executePositionIncrease(
            @NotNull ΩSPLMintAddressΩ tradedTokenMint,
            @NotNull JupiterPerpsPositionDirection direction,
            @NotNull ΩUSDCAmountΩ inputTokenAmount,
            @NotNull ΩUSDCAmountΩ sizeUsdDelta,
            int maxSlippageBps
    ) throws IOException, JupiterTransactionOutcomeException,
            InterruptedException;

    /**
     * Decreases an existing Jupiter Perps position.
     *
     * <p>The service constructs the transaction, asks its configured wallet
     * to sign it, submits it to Jupiter, and independently awaits Solana
     * {@code CONFIRMED} success. A timeout or communication error after
     * submission leaves the on-chain outcome unknown and must not cause an
     * automatic resubmission.</p>
     *
     * @param positionAccount the Jupiter Perps position to decrease
     * @param receiveTokenMint the mint address of the token to receive
     * @param sizeUsdDelta the requested decrease in position size, denominated in USD
     * @param maxSlippageBps the maximum accepted slippage, in basis points
     * @return the independently confirmed Solana transaction signature
     * @throws IllegalArgumentException if an amount, mint, or slippage value is invalid
     * @throws IOException if the transaction cannot be constructed, signed,
     *                     submitted, or confirmed; after submission the
     *                     on-chain outcome can be unknown
     * @throws JupiterTransactionOutcomeException if the submitted transaction
     *         definitively fails on-chain or confirmation times out with an
     *         unknown outcome
     * @throws InterruptedException if the calling thread is interrupted;
     *                              interruption propagates directly
     */
    @NotNull
    ΩSolanaTransactionSignatureΩ executePositionDecrease(
            @NotNull ΩJupiterPerpsPositionAccountΩ positionAccount,
            @NotNull ΩSPLMintAddressΩ receiveTokenMint,
            @NotNull ΩUSDCAmountΩ sizeUsdDelta,
            int maxSlippageBps
    ) throws IOException, JupiterTransactionOutcomeException,
            InterruptedException;
}
