import {
  abi as FACTORY_ABI,
  bytecode as FACTORY_BYTECODE,
} from '@airdao/astra-cl-core/artifacts/contracts/AstraCLFactory.sol/AstraCLFactory.json'
import {
  abi as FACTORY_V2_ABI,
  bytecode as FACTORY_V2_BYTECODE,
} from '@airdao/astra-contracts/artifacts/contracts/core/AstraFactory.sol/AstraFactory.json'
import { Fixture } from 'ethereum-waffle'
import { ethers, waffle } from 'hardhat'
import { ISAMB, MockTimeSwapRouter02 } from '../../typechain'

import SAMB from '../contracts/SAMB.json'
import { Contract } from '@ethersproject/contracts'
import { constants } from 'ethers'

import {
  abi as NFT_POSITION_MANAGER_ABI,
  bytecode as NFT_POSITION_MANAGER_BYTECODE,
} from '@airdao/astra-cl-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'

const sambFixture: Fixture<{ samb: ISAMB }> = async ([wallet]) => {
  const samb = (await waffle.deployContract(wallet, {
    bytecode: SAMB.bytecode,
    abi: SAMB.abi,
  })) as ISAMB

  return { samb }
}

export const classicFactoryFixture: Fixture<{ factory: Contract }> = async ([wallet]) => {
  const factory = await waffle.deployContract(
    wallet,
    {
      bytecode: FACTORY_V2_BYTECODE,
      abi: FACTORY_V2_ABI,
    },
    [constants.AddressZero]
  )

  return { factory }
}

const clCoreFactoryFixture: Fixture<Contract> = async ([wallet]) => {
  return await waffle.deployContract(wallet, {
    bytecode: FACTORY_BYTECODE,
    abi: FACTORY_ABI,
  })
}

export const clRouterFixture: Fixture<{
  samb: ISAMB
  factoryClassic: Contract
  factory: Contract
  nft: Contract
  router: MockTimeSwapRouter02
}> = async ([wallet], provider) => {
  const { samb } = await sambFixture([wallet], provider)
  const { factory: factoryClassic } = await classicFactoryFixture([wallet], provider)
  const factory = await clCoreFactoryFixture([wallet], provider)

  const nft = await waffle.deployContract(
    wallet,
    {
      bytecode: NFT_POSITION_MANAGER_BYTECODE,
      abi: NFT_POSITION_MANAGER_ABI,
    },
    [factory.address, samb.address, constants.AddressZero]
  )

  const router = (await (await ethers.getContractFactory('MockTimeSwapRouter02')).deploy(
    factoryClassic.address,
    factory.address,
    nft.address,
    samb.address
  )) as MockTimeSwapRouter02

  return { samb, factoryClassic, factory, nft, router }
}
