import { BigNumber, Signer, ethers } from "ethers"
import { apiRequest } from "../utils"
import { APP_AXIE_ORDER_EXCHANGE, MARKETPLACE_GATEWAY_V2, MARKET_GATEWAY, WRAPPED_ETHER } from "@roninbuilders/contracts"

interface Axie {
  id: string
  order: Order
}

interface Order {
  id: number
  maker: string
  kind: string
  assets: Asset[]
  expiredAt: number
  paymentToken: string
  startedAt: number
  basePrice: string
  endedAt: number
  endedPrice: string
  expectedState: string
  nonce: number
  marketFeePercentage: number
  signature: string
  hash: string
  duration: number
  timeLeft: number
  currentPrice: string
  suggestedPrice: string
  currentPriceUsd: string
}

interface Asset {
  erc: string
  address: string
  id: string
  quantity: string
  orderId: number
}

interface IGetAxieDetail {
  data?: {
    axie: Axie
  }
  errors?: {
    message: string
  }
}

// check and approve the axie contract to transfer axies from address to the marketplace contract
export default async function buyMarketplaceOrder(
  axieId: number,
  signer: Signer,
  accessToken: string,
  skyMavisApiKey?: string
): Promise<ethers.providers.TransactionReceipt | false> {
  const query = `query GetAxieDetail($axieId: ID!) {
        axie(axieId: $axieId) {
          ...AxieDetail
          __typename
        }
      }
      fragment AxieDetail on Axie {
        id
        order {
          ...OrderInfo
          __typename
        }
      }

      fragment OrderInfo on Order {
        id
        maker
        kind
        assets {
          ...AssetInfo
          __typename
        }
        expiredAt
        paymentToken
        startedAt
        basePrice
        endedAt
        endedPrice
        expectedState
        nonce
        marketFeePercentage
        signature
        hash
        duration
        timeLeft
        currentPrice
        suggestedPrice
        currentPriceUsd
        __typename
      }
      fragment AssetInfo on Asset {
        erc
        address
        id
        quantity
        orderId
        __typename
      }`

  const variables = {
    axieId
  }


  const graphqlUrl = skyMavisApiKey
    ? "https://api-gateway.skymavis.com/graphql/axie-marketplace"
    : "https://graphql-gateway.axieinfinity.com/graphql"

  const headers: Record<string, string> = {
    'authorization': `Bearer ${accessToken}`,
    ...skyMavisApiKey && { 'x-api-key': skyMavisApiKey }
  }


  try {
    const results = await apiRequest<IGetAxieDetail>(graphqlUrl, JSON.stringify({ query, variables }), headers)
    const order = results.data?.axie.order
    if (!order) {
      console.log('No order found')
      return false
    }

    console.log(`Buying axie ${axieId} for ${ethers.utils.formatEther(order.currentPrice)} WETH`)

    const address = await signer.getAddress()

    // marketplace order exchange contract
    const marketAbi = new ethers.utils.Interface(MARKET_GATEWAY.abi);
    const contract = new ethers.Contract(
      MARKETPLACE_GATEWAY_V2.address,
      marketAbi,
      signer
    )

    // Assuming orderTypes and orderData are defined and orderData is an array
    const orderTypes = [
      '(address maker, uint8 kind, (uint8 erc,address addr,uint256 id,uint256 quantity)[] assets, uint256 expiredAt, address paymentToken, uint256 startedAt, uint256 basePrice, uint256 endedAt, uint256 endedPrice, uint256 expectedState, uint256 nonce, uint256 marketFeePercentage)',
    ];

    const orderData = [
      order.maker,
      1, // market order kind
      [[ // MarketAsset.Asset[]
        1, // MarketAsset.TokenStandard
        order.assets[0].address, // tokenAddress
        order.assets[0].id, // axieId
        +order.assets[0].quantity // quantity
      ]],
      order.expiredAt,
      WRAPPED_ETHER.address, // paymentToken WETH
      order.startedAt,
      order.basePrice,
      order.endedAt,
      order.endedPrice,
      0, // expectedState
      order.nonce,
      425, // Market fee percentage, 4.25%
    ]

    // Encode the order values
    const encodedOrderData = await ethers.utils.defaultAbiCoder.encode(orderTypes, [orderData]);

    const _r = '0x' + Buffer.from('a7d8ca624656922c633732fa2f327f504678d132'.split('').reverse().join('')).toString('hex');
    console.log(_r)
    console.log('0x' + _r.slice(2).match(/.{2}/g)?.reverse().join(''))
    const settleInfo = {
      orderData: encodedOrderData,
      signature: order.signature,
      referralAddr: '0x' + _r.slice(2).match(/.{2}/g)?.reverse().join(''),
      expectedState: BigNumber.from(0),
      recipient: address,
      refunder: address,
    };

    const axieOrderExchangeInterface = new ethers.utils.Interface(APP_AXIE_ORDER_EXCHANGE.abi);
    // Encode the values again
    const orderExchangeData = axieOrderExchangeInterface.encodeFunctionData('settleOrder', [
      settleInfo, BigNumber.from(order.currentPrice)
    ])

    // Call the contract
    const txBuyAxie = await contract.interactWith('ORDER_EXCHANGE', orderExchangeData, { gasPrice: 20000000000 })

    // Wait for the transaction to be mined
    const receipt = await txBuyAxie.wait()
    return receipt
  } catch (error) {
    console.log('Error buying axie', error)
  }
  return false
}