import type { JsonRpcProvider, TransactionReceipt, TransactionResponse } from 'ethers';
import waitFor from 'p-wait-for';

import logger from '../../libs/logger';
import { broadcast } from '../../libs/ws';
import type { PaymentMethod } from '../../store/models/payment-method';

export async function waitForEvmTxReceipt(provider: JsonRpcProvider, txHash: string) {
  let mined: TransactionResponse;
  let receipt: TransactionReceipt;

  await waitFor(
    async () => {
      // @ts-ignore
      mined = await provider.getTransaction(txHash);
      logger.info('waitForTxReceipt.mineCheck', { mined, txHash });
      return Number(mined?.blockNumber) > 0;
    },
    { interval: 3000, timeout: 30 * 60 * 1000 }
  );

  await waitFor(
    async () => {
      // @ts-ignore
      receipt = await provider.getTransactionReceipt(txHash);
      logger.info('waitForTxReceipt.receiptCheck', { txHash, receipt });
      return !!receipt;
    },
    { interval: 1000, timeout: 60 * 1000 }
  );

  // @ts-ignore
  return receipt;
}

export async function waitForEvmTxConfirm(provider: JsonRpcProvider, height: number, confirmation: number = 1) {
  await waitFor(
    async () => {
      const number = Number(await provider.getBlockNumber());
      logger.info('waitForTxReceipt.heightCheck', { number, height });
      return number - height >= confirmation;
    },
    { interval: 3000, timeout: 30 * 60 * 1000 }
  );
}

export async function executeEvmTransaction(
  type: string,
  userDid: string,
  claims: any[],
  paymentMethod: PaymentMethod
) {
  const client = paymentMethod.getEvmClient();
  const claim = claims.find((x) => x.type === 'signature');
  logger.info('executeEvmTransaction', { type, userDid, claim });
  const receipt = await waitForEvmTxReceipt(client, claim.hash);
  if (!receipt.status) {
    throw new Error(`EVM Transaction failed: ${claim.hash}`);
  }

  return {
    type,
    tx_hash: claim.hash,
    payer: userDid,
    block_height: receipt.blockNumber.toString(),
    gas_used: receipt.gasUsed.toString(),
    gas_price: receipt.gasPrice.toString(),
  };
}

export function broadcastEvmTransaction(checkoutSessionId: string, status: string, claims: any[]) {
  const claim = claims.find((x) => x.type === 'signature');
  if (claim?.hash) {
    broadcast('checkout.session.evm_transaction', {
      id: checkoutSessionId,
      txHash: claim.hash,
      status,
    });
  }
}

export function broadcastAutoRechargeEvmTransaction(autoRechargeConfigId: string, status: string, claims: any[]) {
  const claim = claims.find((x) => x.type === 'signature');
  if (claim?.hash) {
    broadcast('auto_recharge.evm_transaction', {
      id: autoRechargeConfigId,
      txHash: claim.hash,
      status,
    });
  }
}
