import {FastifyPluginAsyncTypebox} from '@fastify/type-provider-typebox'
import {Type} from '@sinclair/typebox'
import {TradeDirection} from '../../../generated/ManagingApiTypes'
import {
    getClaimableFundingFeesImpl,
    getClaimableUiFeesImpl,
    getGmxRebateStatsImpl
} from '../../../plugins/custom/gmx.js'

const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
  // Define route to open a position
  fastify.post('/open-position', {
    schema: {
      body: Type.Object({
        account: Type.String(),
        tradeType: Type.String(),
        ticker: Type.String(),
        direction: Type.String(),
        price: Type.Optional(Type.Number()),
        quantity: Type.Number(),
        leverage: Type.Number(),
        stopLossPrice: Type.Optional(Type.Number()),
        takeProfitPrice: Type.Optional(Type.Number())
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          hash: Type.Optional(Type.String()),
          error: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    const { account, tradeType, ticker, direction, price, quantity, leverage, stopLossPrice, takeProfitPrice } = request.body
    
    // Call the openPosition method from the GMX plugin
    return request.openGmxPosition(
      reply,
      account,
      tradeType,
      ticker,
      direction as TradeDirection,
      price,
      quantity,
      leverage,
      stopLossPrice,
      takeProfitPrice
    )
  })

  // Define route to cancel orders
  fastify.post('/cancel-orders', {
    schema: {
      body: Type.Object({
        account: Type.String(),
        ticker: Type.String()
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          error: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    const { account, ticker } = request.body
    
    // Call the cancelGmxOrders method from the GMX plugin
    return request.cancelGmxOrders(
      reply,
      account,
      ticker,
    )
  })

  // Define route to close a position
  fastify.post('/close-position', {
    schema: {
      body: Type.Object({
        account: Type.String(),
        ticker: Type.String(),
        direction: Type.String()
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          hash: Type.Optional(Type.String()),
          error: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    const { account, ticker, direction } = request.body
    
    // Call the closePosition method from the GMX plugin
    return request.closeGmxPosition(
      reply,
      account,
      ticker,
      direction as TradeDirection
    )
  })

  // Define route to swap tokens
  fastify.post('/swap-tokens', {
    schema: {
      body: Type.Object({
        account: Type.String(),
        fromTicker: Type.String(),
        toTicker: Type.String(),
        amount: Type.Number(),
        orderType: Type.Optional(Type.Union([Type.Literal('market'), Type.Literal('limit')])),
        triggerRatio: Type.Optional(Type.Number()),
        allowedSlippage: Type.Optional(Type.Number())
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          hash: Type.Optional(Type.String()),
          message: Type.Optional(Type.String()),
          error: Type.Optional(Type.String()),
          errorType: Type.Optional(Type.String()),
          suggestion: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    const { account, fromTicker, toTicker, amount, orderType, triggerRatio, allowedSlippage } = request.body
    
    // Call the swapGmxTokens method from the GMX plugin
    return request.swapGmxTokens(
      reply,
      account,
      fromTicker,
      toTicker,
      amount,
      orderType || 'market',
      triggerRatio,
      allowedSlippage || 0.5
    )
  })

  // Define route to get a trade
  fastify.get('/trades', {
    schema: {
      querystring: Type.Object({
        account: Type.String(),
        ticker: Type.String()
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          trades: Type.Optional(Type.Array(Type.Any())),
          error: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    const { account, ticker } = request.query
    
    // Call the getGmxTrade method from the GMX plugin
    const result = await request.getGmxTrade(
      reply,
      account,
      ticker
    )

    console.log('result', result)
    
    return result
  })

  // Define route to get positions
  fastify.get('/positions', {
    schema: {
      querystring: Type.Object({
        account: Type.String()
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          positions: Type.Optional(Type.Array(Type.Any())), // Using Type.Any() for now
          error: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    const { account } = request.query
    
    // Call the getGmxPositions method from the GMX plugin
    return request.getGmxPositions(
      reply,
      account
    )
  })

  // Define route to get all claimable fees and rebate stats
  fastify.get('/claimable-summary', {
    schema: {
      querystring: Type.Object({
        account: Type.String()
      }),
      response: {
        200: Type.Object({
          success: Type.Boolean(),
          data: Type.Optional(Type.Object({
            claimableFundingFees: Type.Object({
              totalUsdc: Type.Number()
            }),
            claimableUiFees: Type.Object({
              totalUsdc: Type.Number()
            }),
            rebateStats: Type.Object({
              totalRebateUsdc: Type.Number(),
              discountUsdc: Type.Number(),
              rebateFactor: Type.Number(),
              discountFactor: Type.Number()
            })
          })),
          error: Type.Optional(Type.String())
        })
      }
    }
  }, async (request, reply) => {
    try {
      const { account } = request.query
      
      // Get GMX client for the account
      const sdk = await request.getClientForAddress(account)
      
      // Call all three implementation functions in parallel
      const [fundingFeesData, uiFeesData, rebateStatsData] = await Promise.all([
        getClaimableFundingFeesImpl(sdk),
        getClaimableUiFeesImpl(sdk),
        getGmxRebateStatsImpl(sdk)
      ])

      // Process funding fees data - only calculate totals
      let totalFundingLong = 0
      let totalFundingShort = 0
      
      if (fundingFeesData) {
        Object.values(fundingFeesData).forEach(marketData => {
          totalFundingLong += marketData.claimableFundingAmountLong
          totalFundingShort += marketData.claimableFundingAmountShort
        })
      }

      // Process UI fees data - only calculate totals
      let totalUiFees = 0
      
      if (uiFeesData) {
        Object.values(uiFeesData).forEach(marketData => {
          totalUiFees += marketData.claimableUiFeeAmount
        })
      }

      return {
        success: true,
        data: {
          claimableFundingFees: {
            totalUsdc: totalFundingLong + totalFundingShort
          },
          claimableUiFees: {
            totalUsdc: totalUiFees
          },
          rebateStats: {
            totalRebateUsdc: rebateStatsData?.totalRebateUsd || 0,
            discountUsdc: rebateStatsData?.discountUsd || 0,
            rebateFactor: rebateStatsData?.rebateFactor || 0,
            discountFactor: rebateStatsData?.discountFactor || 0
          }
        }
      }
    } catch (error) {
      console.error('Error getting claimable summary:', error)
      return {
        success: false,
        error: `Failed to get claimable summary: ${error instanceof Error ? error.message : 'Unknown error'}`
      }
    }
  })
}

export default plugin 