import {FastifyPluginAsyncTypebox, Type} from '@fastify/type-provider-typebox'
import {handleError} from '../../../utils/errorHandler.js'
import {TOKENS} from '../../../generated/gmxsdk/configs/tokens.js'
import {ARBITRUM} from '../../../generated/gmxsdk/configs/chains.js'
import {Ticker} from '../../../generated/ManagingApiTypes.js'

const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
  fastify.post(
    '/sign-message',
    {
      schema: {
        body: Type.Object({
          walletId: Type.String(),
          message: Type.String(),
          address: Type.String()
        }),
        response: {
          200: Type.Object({
            success: Type.Boolean(),
            signature: Type.Optional(Type.String()),
            error: Type.Optional(Type.String())
          }),
          400: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          }),
          500: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          })
        },
        tags: ['Privy']
      }
    },
    async function (request, reply) {
      try {
        const { walletId, message, address } = request.body;
        return await request.signPrivyMessage(reply, walletId, message, address);
      } catch (error) {
        return handleError(request, reply, error, 'privy/sign-message');
      }
    }
  )

  fastify.post(
    '/init-address',
    {
      schema: {
        body: Type.Object({
          address: Type.String()
        }),
        response: {
          200: Type.Object({
            success: Type.Boolean(),
            usdcHash: Type.Optional(Type.String()),
            orderVaultHash: Type.Optional(Type.String()),
            exchangeRouterHash: Type.Optional(Type.String()),
            error: Type.Optional(Type.String())
          }),
          400: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          }),
          500: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          })
        },
        tags: ['Privy']
      }
    },
    async function (request, reply) {
      try {
        const { address } = request.body;
        return await request.initAddress(reply, address);
      } catch (error) {
        return handleError(request, reply, error, 'privy/init-address');
      }
    }
  )

  fastify.post(
    '/send-token',
    {
      schema: {
        body: Type.Object({
          senderAddress: Type.String(),
          recipientAddress: Type.String(),
          ticker: Type.String(),
          amount: Type.String(), // Using string for bigint compatibility
          chainId: Type.Optional(Type.Number())
        }),
        response: {
          200: Type.Object({
            success: Type.Boolean(),
            hash: Type.Optional(Type.String()),
            error: Type.Optional(Type.String())
          }),
          400: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          }),
          500: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          })
        },
        tags: ['Privy']
      }
    },
    async function (request, reply) {
      try {
        const { senderAddress, recipientAddress, ticker, amount, chainId } = request.body;
        
        // Handle decimal numbers with comma separators and convert to proper token units
        let amountBigInt: bigint;
        
        if (typeof amount === 'string') {
          // Replace comma with period for decimal parsing
          const normalizedAmount = amount.replace(',', '.');
          
          // Parse as float first
          const amountFloat = parseFloat(normalizedAmount);
          
          if (isNaN(amountFloat)) {
            throw new Error(`Invalid amount format: ${amount}`);
          }
          
          // Get token decimals from GMX configuration
          const chainTokens = TOKENS[ARBITRUM];
          const token = chainTokens.find(t => t.symbol === ticker);
          
          if (!token) {
            throw new Error(`Token not found: ${ticker}`);
          }
          
          const tokenDecimals = token.decimals;
          const amountInSmallestUnit = Math.floor(amountFloat * Math.pow(10, tokenDecimals));
          
          amountBigInt = BigInt(amountInSmallestUnit);
        } else {
          amountBigInt = BigInt(amount);
        }
        
        return await request.sendToken(reply, senderAddress, recipientAddress, ticker, amountBigInt, chainId);
      } catch (error) {
        return handleError(request, reply, error, 'privy/send-token');
      }
    }
  )

  fastify.get(
    '/wallet-balance',
    {
      schema: {
        querystring: Type.Object({
          address: Type.String(),
          asset: Type.Union([Type.String(), Type.Array(Type.String())]), // Can be single or array
          chain: Type.Union([Type.String(), Type.Array(Type.String())]) // Can be single or array
        }),
        response: {
          200: Type.Object({
            success: Type.Boolean(),
            balances: Type.Optional(Type.Array(Type.Object({
              tokenImage: Type.Optional(Type.String()),
              tokenName: Type.Optional(Type.String()),
              amount: Type.Optional(Type.Number()),
              price: Type.Optional(Type.Number()),
              value: Type.Optional(Type.Number()),
              tokenAdress: Type.Optional(Type.String()),
              chain: Type.Optional(Type.Object({
                id: Type.Optional(Type.String()),
                rpcUrl: Type.Optional(Type.String()),
                name: Type.Optional(Type.String()),
                chainId: Type.Optional(Type.Number())
              }))
            }))),
            error: Type.Optional(Type.String())
          }),
          400: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          }),
          500: Type.Object({
            success: Type.Boolean(),
            error: Type.String()
          })
        },
        tags: ['Privy']
      }
    },
    async function (request, reply) {
      try {
        const { address, asset, chain } = request.query;
        
        // Convert single values to arrays if needed
        const assetsArray = Array.isArray(asset) ? asset : [asset];
        const chainsArray = Array.isArray(chain) ? chain : [chain];
        
        // Convert asset strings to Ticker enums
        const assetEnums = assetsArray.map(a => a as Ticker);
        
        return await request.getWalletBalance(reply, address, assetEnums, chainsArray);
      } catch (error) {
        return handleError(request, reply, error, 'privy/wallet-balance');
      }
    }
  )
}

export default plugin 