import contracts from "./contracts"
import oneSidedStaking from "../artifacts/contracts/staking/OneSidedStaking.sol/OneSidedStaking.json"
import {initContractByAbi} from "./utils"
import {Event} from "ethers"

const ONE_SIDED_STAKING_CONTRACT = 'one_sided_staking'

const abi = () => {
  return oneSidedStaking.abi
}

const bytecode = () => {
  return oneSidedStaking.bytecode
}

const deployedAddress = (network : string | number) => {
  if (!contracts[`${network}`]) return null
  return contracts[`${network}`][ONE_SIDED_STAKING_CONTRACT]
}

const initContract = (contractKey : string, readOnly = true, web3Provider = null) => {
  return initContractByAbi(oneSidedStaking.abi, contractKey, readOnly, web3Provider)
}

const owner = (web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, true, web3Provider)
    .then(contract => contract.owner())
}

const pendingRewards = (address : string, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, true, web3Provider)
    .then(contract => contract.pendingRewards(address))
}

const claim = (web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, false, web3Provider)
    .then(contract => contract.claim())
}

const claimAllUnstaked = (web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, false, web3Provider)
    .then(contract => contract.claimAllUnstaked())
}

const claimUnstaked = (ticket : number, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, false, web3Provider)
    .then(contract => contract.claimUnstaked(ticket))
}

const stake = (amount : number, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, false, web3Provider)
    .then(contract => contract.stake(amount))
}

const unstake = (amount : number, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, false, web3Provider)
    .then(contract => contract.unstake(amount))
}

const depositInfo = (address : string, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, true, web3Provider)
    .then(contract => contract.depositInfo(address))
}

const unstakingRequests = (address : string, index : number, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, true, web3Provider)
    .then(contract => contract.unstakingRequests(address, index))
}

const getWalletUnstakingRequests = (address : string, web3Provider = null, contractKey = ONE_SIDED_STAKING_CONTRACT) => {
  return initContract(contractKey, true, web3Provider)
    .then(contract => Promise.all([
      contract.queryFilter(contract.filters.UnstakeRequest(address)),
      contract.queryFilter(contract.filters.UnstakedWithdrawn(address)),
    ]))
    .then(([requests, claimed]) => {
      const claimedTickets = claimed.map((event) => event.args ? event.args._ticket.toNumber() : null)
      return requests.reduce((acc : Event[], event) => {
        if (!event.args || event.args._ticket.toNumber() in claimedTickets) {
          return acc
        } else {
          acc.push(event)
          return acc
        }
      }, [])
    })
}

export {
  abi,
  bytecode,
  deployedAddress,
  owner,
  pendingRewards,
  claim,
  claimAllUnstaked,
  claimUnstaked,
  stake,
  unstake,
  depositInfo,
  unstakingRequests,
  getWalletUnstakingRequests
}
export default {
  abi,
  bytecode,
  deployedAddress,
  owner,
  pendingRewards,
  claim,
  claimAllUnstaked,
  claimUnstaked,
  stake,
  unstake,
  depositInfo,
  unstakingRequests,
  getWalletUnstakingRequests
}