import { web3 } from "hardhat";
import History from "./interface/history";
import contracts from "../config/contracts";
import logger from "../utils/logger";
import v2_routers from "../config/v2_routers";
import {BigNumber} from "ethers";
import {replaceAll} from "hardhat/internal/util/strings";

async function handlePosition(router: String, factory: String) {
  try {
    // 拉取当前pull状态信息
    const pullState = await History.findByHashOrBlockOrDataVague('UNIV2DEX', factory, '', 0, 200)
    let nowPosition = 0

    // 没有状态信息的情况
    if (pullState.data.length == 0) {
      const appendRst = await History.appendOrUpdate('UNIV2DEX', factory, {"now": nowPosition})
      logger.debug(appendRst)
    } else {
      nowPosition = pullState.data[0].dataObj.now
    }

    return nowPosition
  } catch (e) {
    logger.error(`Pull state error, router: ${router}, factory: ${factory}`)
    logger.error(e)
  }

  return 0
}

async function handleAFactory(router: String, factory: String, position: number, pairsLength: number, v2_410_tool: any) {
  let errorCount = 0

  while (position <= pairsLength) {
    try {
      const info = await v2_410_tool.methods.getPairIdInfo(factory, position).call()

      // return (
      //  0   pairInfo.lp,
      //  1   pairInfo.token0,
      //  2   pairInfo.symbol0,
      //  3   pairInfo.decimals0,
      //  4   pairInfo.r0,
      //  5   pairInfo.token1,
      //  6   pairInfo.symbol1,
      //  7   pairInfo.decimals1,
      //  8   pairInfo.r1
      // );

      const symbol0 = info['2'].replace(/[^A-Za-z0-9 ]+/g, '').substring(0, 10)
      const symbol1 = info['6'].replace(/[^A-Za-z0-9 ]+/g, '').substring(0, 10)
      const name = `${router.slice(2, 4) + router.slice(-2)}_${symbol0}_${symbol1}`
      const sum2 = replaceAll(BigNumber.from(info['1']).add(BigNumber.from(info['5']))._hex, '0x0', '0x')

      const data = {
        LP: info['0'],
        decimals0: info['3'],
        decimals1: info['7'],
        factory: factory,
        feei: 30,
        id: position,
        name: name,
        r0: info['4'],
        r1: info['8'],
        router: router,
        sum2: sum2,
        symbol0: symbol0,
        symbol1: symbol1,
        token0: info['1'],
        token1: info['5']
      }
      const insertRst = await History.appendOrUpdate('0', info['0'], data)
      logger.debug(insertRst.msg, `, hash: ${info['0']}, ${position} / ${pairsLength}`)

      // 每十次更新一次position
      if (position % 50 == 0) {
        await History.appendOrUpdate('UNIV2DEX', factory, {"now": position})
        logger.debug(`Position updated: ${position}`)
      }

      errorCount = 0
    } catch (e) {
      logger.error(JSON.stringify(e))
      errorCount++
    }

    position++
    if (errorCount >= 5) {
      position = position - 5
      break;
    }
  }
}

async function main() {
  const fromZero: boolean = true

  logger.debug('Pull v2 start.')

  const v2_router_abi = require('../abi/UNIV2_ROUTER_ABI.json')
  const v2_factory_abi = require('../abi/UNIV2_FACTORY_ABI.json')
  const v2_tool_abi = require('../abi/410_V2_TOOLS.json')

  // 初始化410 v2工具箱
  const v2_410_tool = new web3.eth.Contract(v2_tool_abi, contracts.TOOLS_410_V2)

  for (let router_index = 0; router_index < v2_routers.length; router_index++) {
    const v2_router_address = v2_routers[router_index]

    try {
      logger.debug(`Router address: ${v2_router_address}`)

      // 获取工厂地址
      const v2_router = new web3.eth.Contract(v2_router_abi, v2_router_address)
      const v2_factory_address = await v2_router.methods.factory().call()
      // 获取工厂实例
      const v2_factory = new web3.eth.Contract(v2_factory_abi, v2_factory_address)
      // 获取当前pairsLength
      const pairsLength = await v2_factory.methods.allPairsLength().call()
      // 获取当前pull状态
      const position = fromZero ? 0 : await handlePosition(v2_router_address, v2_factory_address)

      logger.debug(`factory: ${v2_factory_address}, ${position} / ${pairsLength}.`)
      await handleAFactory(v2_router_address, v2_factory_address, position, pairsLength, v2_410_tool)
    } catch (e) {
      logger.error(`New contract error, router: ${v2_router_address}`)
      logger.error(e)
    }
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
})
