import BalanceTree from './balance-tree'
import { BigNumber, ethers } from 'ethers'
import { getWeb3Provider, ERC721Holder, ConditionalDistributor, Le7elEvents } from './lib'
const Buffer = require('buffer/').Buffer

declare global {
  interface Window {
    Le7elEvents: any;
    ethereum: ethers.providers.ExternalProvider | ethers.providers.JsonRpcFetchFunc | undefined;
  }
}

let balance : BalanceTree | null
balance = null

function parseProof(str : string) {
  return Buffer.from(str.slice('0x'.length), 'hex')
}

window.Le7elEvents = Le7elEvents

document.getElementById('js-distributions')?.addEventListener('submit', (event) => {
  event.preventDefault()
  const input = document.getElementById('js-json_distributions') as HTMLInputElement | null
  const json_distributions = input?.value
  if (!json_distributions || json_distributions.length < 1) return

  const data = JSON.parse(json_distributions)
  balance = new BalanceTree(data)
  const root = document.getElementById('js-merkle_root') as HTMLInputElement | null
  if (root) root.value = balance.getHexRoot()
  const verify = document.getElementById('js-root-verify') as HTMLInputElement | null
  if (verify) verify.value = balance.getHexRoot()

  const proofBlock = document.getElementById('js-proofs') as HTMLElement | null
  if (proofBlock) proofBlock.style.display = 'block'

  return false
})

document.getElementById('js-proofs')?.addEventListener('submit', (event) => {
  event.preventDefault()
  if (!balance) return
  if (!event.target) return

  const formData = new FormData(event.target as HTMLFormElement)
  const index = BigNumber.from(formData.get("index"))
  const account = formData.get("account")?.toString()
  const amount = BigNumber.from(formData.get("amount"))
  if (!account) return

  const proof = JSON.stringify(balance.getProof(index, account, amount))
  const proofInput = document.getElementById('js-proof') as HTMLInputElement | null
  if (proofInput) proofInput.value = proof
  const verify = document.getElementById('js-proof-verify') as HTMLInputElement | null
  if (verify) verify.value = proof

  return false
})

document.getElementById('js-proof-verification')?.addEventListener('submit', (event) => {
  event.preventDefault()
  if (!balance) return
  if (!event.target) return
  const verificationResult = document.getElementById('js-verification') as HTMLElement | null
  if (!verificationResult) return
  verificationResult.innerHTML = 'verifing...'

  const formData = new FormData(event.target as HTMLFormElement)
  const index = BigNumber.from(formData.get("index"))
  const account = formData.get("account")?.toString()
  const amount = BigNumber.from(formData.get("amount"))
  const root = formData.get("root")?.toString()
  const claimProof = formData.get("proof")?.toString()
  if (!account || !root || !claimProof) return
  const claimProofs = JSON.parse(claimProof).map((v : string) => parseProof(v))

  const result = BalanceTree.verifyProof(index, account, amount, claimProofs, parseProof(root))
  if (result) {
    verificationResult.innerHTML = 'VALID PROOF'
  } else {
    verificationResult.innerHTML = 'INVALID PROOF'
  }

  return false
})

document.getElementById('js-conditional-proof')?.addEventListener('submit', (event) => {
  event.preventDefault()
  if (!event.target) return

  const formData = new FormData(event.target as HTMLFormElement)
  const account = formData.get("account")?.toString()
  const id = BigNumber.from(formData.get("id"))
  const token = formData.get("token")?.toString()
  const tokenId = BigNumber.from(formData.get("token_id"))
  const claimInterface = formData.get("claim_interface")?.toString()
  if (!id || !token || !tokenId || !claimInterface) return

  const claimResult = document.getElementById('js-conditional-claim-progress') as HTMLElement | null

  if (event.submitter?.getAttribute('name') === 'check_reward') {
    const claim = formData.get("claim")?.toString()
    if (!account || !claim) return
    
    if (!claimResult) return
    claimResult.innerHTML = 'checking reward...'

    Promise.all([ERC721Holder.getReward(id), ERC721Holder.hasClaim(account, claim)])
      .then(([reward, valid]) => {
        if (!valid) {
          claimResult.innerHTML = 'invalid claim'
        } else if (reward.eq(BigNumber.from(0))) {
          claimResult.innerHTML = 'no reward'
        } else {
          claimResult.innerHTML = reward.toString()
        }
      })
      .catch((error) => {
        console.log(error)
        claimResult.innerHTML = error.reason
      })
  }

  if (event.submitter?.getAttribute('name') === 'execute_claim') {
    const claim = formData.get("claim")?.toString()
    if (!account || !claim) return
    
    if (!claimResult) return
    claimResult.innerHTML = 'claiming reward...'

    getWeb3Provider()
      .then((provider) => {
        if (!(provider instanceof ethers.providers.Web3Provider)) return

        return provider.send("eth_requestAccounts", [])
          .then(() => {
            ConditionalDistributor.claim(
              account,
              ERC721Holder.deployedAddress(4) || "",
              claimInterface,
              token,
              tokenId,
              claim
            )
            .then((tr) => provider.waitForTransaction(tr.hash))
            .then(() => {
              claimResult.innerHTML = 'reward claimed!'
            })
            .catch((error) => {
              console.log(error)
              claimResult.innerHTML = error.reason
            })
          })
      })
  }

  if (event.submitter?.getAttribute('name') === 'generate_claim') {
    if (!claimResult) return
    claimResult.innerHTML = 'generating...'

    ERC721Holder.prepareClaim(claimInterface, token, tokenId, id)
      .then((claim) => {
        const proofInput = document.getElementById('js-conditional-claim') as HTMLInputElement | null
        if (proofInput) proofInput.value = claim
        claimResult.innerHTML = 'ready'
      })
      .catch((error) => {
        console.log(error)
        claimResult.innerHTML = error.reason
      })
  }

  return false
})