import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import { Swap, poolUtils, SwapType } from '@tinymanorg/tinyman-js-sdk';
import { getAlgodClient, extractNetwork } from '../../../algorand-client.js';
import { withCommonParams } from '../../commonParams.js';
export const swapTools = [
    {
        name: 'api_tinyman_get_swap_quote',
        description: 'Get quote for swapping assets',
        inputSchema: withCommonParams({
            type: 'object',
            properties: {
                assetIn: {
                    type: 'integer',
                    description: 'ID of the input asset'
                },
                assetOut: {
                    type: 'integer',
                    description: 'ID of the output asset'
                },
                amount: {
                    type: 'integer',
                    description: 'Amount to swap'
                },
                mode: {
                    type: 'string',
                    enum: ['fixedInput', 'fixedOutput'],
                    description: 'Mode of swap'
                },
                version: {
                    type: 'string',
                    enum: ['v1_1', 'v2'],
                    description: 'Tinyman protocol version',
                    default: 'v2'
                }
            },
            required: ['assetIn', 'assetOut', 'amount', 'mode']
        })
    }
];
export async function handleSwapTools(args) {
    const { name, assetIn, assetOut, amount, mode, version = 'v2' } = args;
    const network = extractNetwork(args);
    const algodClient = getAlgodClient(network);
    if (network === 'localnet') {
        throw new McpError(ErrorCode.InvalidRequest, 'Tinyman is not available on localnet');
    }
    const tinymanNetwork = network;
    async function getAssetDecimals(assetId) {
        try {
            if (assetId === 0)
                return 6; // Algo has 6 decimals
            const assetInfo = await algodClient.getAssetByID(assetId).do();
            return assetInfo.params.decimals;
        }
        catch (error) {
            console.error(`Failed to get decimals for asset ${assetId}:`, error);
            return 6; // Default to 6 decimals if we can't get the info
        }
    }
    if (name === 'api_tinyman_get_swap_quote') {
        try {
            // Get pool information first
            const poolInfo = await (version === 'v2'
                ? poolUtils.v2.getPoolInfo({
                    client: algodClient,
                    network: tinymanNetwork,
                    asset1ID: assetIn,
                    asset2ID: assetOut
                })
                : poolUtils.v1_1.getPoolInfo({
                    client: algodClient,
                    network: tinymanNetwork,
                    asset1ID: assetIn,
                    asset2ID: assetOut
                }));
            // Get asset decimals
            const [assetInDecimals, assetOutDecimals] = await Promise.all([
                getAssetDecimals(assetIn),
                getAssetDecimals(assetOut)
            ]);
            let quote;
            if (version === 'v2') {
                if (mode === 'fixedInput') {
                    quote = await Swap.v2.getQuote({
                        assetIn: {
                            id: assetIn,
                            decimals: assetInDecimals
                        },
                        assetOut: {
                            id: assetOut,
                            decimals: assetOutDecimals
                        },
                        pool: poolInfo,
                        amount: BigInt(amount),
                        type: SwapType.FixedInput,
                        network: tinymanNetwork,
                        slippage: 0.01 // 1% slippage
                    });
                }
                else {
                    quote = await Swap.v2.getQuote({
                        assetIn: {
                            id: assetIn,
                            decimals: assetInDecimals
                        },
                        assetOut: {
                            id: assetOut,
                            decimals: assetOutDecimals
                        },
                        pool: poolInfo,
                        amount: BigInt(amount),
                        type: SwapType.FixedOutput,
                        network: tinymanNetwork,
                        slippage: 0.01
                    });
                }
            }
            else {
                // Get pool reserves for v1.1
                const reserves = await poolUtils.v1_1.getPoolReserves(algodClient, poolInfo);
                if (mode === 'fixedInput') {
                    quote = Swap.v1_1.getQuote(SwapType.FixedInput, poolInfo, reserves, {
                        id: assetIn,
                        amount: BigInt(amount)
                    }, {
                        assetIn: assetInDecimals,
                        assetOut: assetOutDecimals
                    });
                }
                else {
                    quote = Swap.v1_1.getQuote(SwapType.FixedOutput, poolInfo, reserves, {
                        id: assetOut,
                        amount: BigInt(amount)
                    }, {
                        assetIn: assetInDecimals,
                        assetOut: assetOutDecimals
                    });
                }
            }
            return quote;
        }
        catch (error) {
            throw new McpError(ErrorCode.InternalError, `Failed to get swap quote: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    throw new McpError(ErrorCode.MethodNotFound, `Unknown swap tool: ${name}`);
}
