/* eslint-disable @typescript-eslint/return-await */
/* eslint-disable consistent-return */
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/ban-ts-comment */
// eslint-disable-next-line import/no-unresolved
import { SupportedNetworkId } from "@leekone/bnsjs/contracts/types";
import { sendTransaction, switchNetwork, waitForTransaction } from "@wagmi/core";
import BigNumberNoEther from "bignumber.js";
import { BigNumber } from "ethers/lib/ethers";
import { useCallback, useEffect, useState } from "react";
import { useAccount, useBalance, useNetwork, usePublicClient } from "wagmi";

import { BNSContext } from "../../BNSProvider";
import { findCoinByAddress } from "../utils/coins";
import addresses from "../utils/contracts";
import { getAddress, randomSecret, toFixed } from "../utils/util";
import { useUsdtERC20 } from "./useContract";
import useProviderOrSigner from "./useProviderOrSigner";

export type RegisterData = {
  name: string;
  owner: string;
  duration: number;
  secret?: string;
  resolver?: string;
  data?: string[];
  reverseRecord?: boolean;
  ownerControlledFuses?: number;
  rebateName?: string;
};

export default function useBiu() {
  const bns = BNSContext();

  const [priceLoading, setPriceLoading] = useState(false);
  const [balance, setBalance] = useState("");
  const [balanceMatic, setBalanceMatic] = useState("");
  const erc20Contract = useUsdtERC20();
  const { chain } = useNetwork();
  const { address } = useAccount();
  const signer = useProviderOrSigner();
  const provider = usePublicClient();
  const chainID = process.env.NODE_ENV === "production" ? "137" : "137";
  const [prices, setPrices] = useState<BigNumber[]>([BigNumber.from(0), BigNumber.from(0)]);

  const { data } = useBalance({
    address,
  });

  const waitTransaction = async (hash: string) => {
    const res = await waitForTransaction({ hash: hash as `0x${string}` });
    if (data) {
      if (res.status === "success") {
        return true;
      }
      return false;
    }
    return false;
  };

  const switchChain = async () => {
    if (`${chain?.id}` !== chainID) {
      try {
        const res = await switchNetwork({
          chainId: Number(chainID),
        });
        return res;
      } catch (error) {
        return new Promise((resolve) => {
          resolve({ id: "" });
        });
      }
    } else {
      return new Promise((resolve) => {
        resolve({ id: chainID });
      });
    }
  };

  const getBalance = useCallback(async () => {
    const res = await erc20Contract.balanceOf(address as string);
    const coin = findCoinByAddress(getAddress(addresses.usdt, chain?.id));
    setBalance(new BigNumberNoEther(res.toString()).div(10 ** (coin?.decimals || 18)).toFixed(2));
  }, [address, chain?.id, erc20Contract]);

  useEffect(() => {
    setBalanceMatic(`${toFixed(Number(data?.formatted || 0), 2)}`);
    getBalance();
  }, [address, chain?.id, data]);

  const registerName = async (name: string, rebateName: string, owner: string, coin: string, price: BigNumber, isMain: boolean) => {
    const res = { duration: 0, owner, rebateName, secret: randomSecret() };
    const popuData: any = {
      signer: signer as any,
      resolverAddress: "",
      ...res,
      value: coin === "0x0" ? new BigNumberNoEther(price.toString()).times(1.001).toFixed(0) : BigNumber.from(0),

      // @ts-ignore
      rebateName: `${rebateName}`.replaceAll(".biu", ""),
      isERC20: coin !== "0x0",
      reverseRecord: true,
    };
    if (!isMain) {
      popuData.records = { coinTypes: [{ key: "MATIC", value: owner }] };
      delete popuData.reverseRecord;
    }
    const populatedTransaction = await bns.registerName.populateTransaction(name, popuData);
    const gasLimit = await provider.estimateGas({ account: address, to: populatedTransaction.to as `0x${string}`, ...(populatedTransaction as any) });
    const { hash } = await sendTransaction({
      account: address,
      to: populatedTransaction.to as `0x${string}`,
      ...(populatedTransaction as any),
      gas: gasLimit,
    });
    return hash;
  };

  const getPrices = async (name: string, needLoading: boolean) => {
    try {
      if (needLoading) {
        setPriceLoading(true);
      }
      const res = await Promise.all([
        (await bns.getPrice(name.split(".")[0], 0))?.base || BigNumber.from(0),
        (await bns.getUsdPrice(name.split(".")[0], 0))?.base || BigNumber.from(0),
      ]);
      setPrices(res);
      setPriceLoading(false);

      return res;
    } catch (error) {
      console.error(error);
      setPriceLoading(false);

      return [BigNumber.from(0), BigNumber.from(0)];
    }
  };

  const getControlContact = async () => {
    try {
      return await bns.getContractAddress(chainID as SupportedNetworkId)("ETHRegistrarController");
    } catch (error) {}
  };

  const transferName = async (name: string, newOwner: string) => {
    try {
      const populatedTransaction = await bns.transferName.populateTransaction(name, { newOwner, contract: "nameWrapper", signer });

      const { hash } = await sendTransaction({
        account: address,
        to: populatedTransaction.to as `0x${string}`,
        ...(populatedTransaction as any),
      });
      return { hash };
    } catch (error) {
      console.warn(error);
    }
  };
  const getName = async (addr?: string) => {
    try {
      return await bns.getName((addr || address) as string);
    } catch (error) {
      console.warn(error);
    }
  };

  const setName = async (name: string) => {
    try {
      const populatedTransaction = await bns.setName.populateTransaction(name as string, { address, signer: signer as any });

      const { hash } = await sendTransaction({
        account: address,
        to: populatedTransaction.to as `0x${string}`,
        ...(populatedTransaction as any),
      });

      return { hash };
    } catch (error) {
      console.warn(error);
    }
  };

  return {
    switchChain,
    getControlContact,
    getPrices,
    registerName,
    balance,
    waitTransaction,
    transferName,
    balanceMatic,
    getName,
    setName,
    chain,
    chainID,
    prices,
    priceLoading,
  };
}
