import { useEffect } from "react"
import { useTargetNetwork } from "./useTargetNetwork"
import {
  QueryObserverResult,
  RefetchOptions,
  useQueryClient,
} from "@tanstack/react-query"
import type { ExtractAbiFunctionNames } from "abitype"
import { ReadContractErrorType } from "viem"
import { useBlockNumber, useReadContract } from "wagmi"
import { useDeployedContractInfo } from "~~/hooks/xchange-create"
import {
  AbiFunctionReturnType,
  ContractAbi,
  ContractName,
  UseReadConfig,
} from "~~/utils/xchange/contract"

/**
 * Wrapper around wagmi's useContractRead hook which automatically loads (by name) the contract ABI and address from
 * the contracts present in deployedContracts.ts & externalContracts.ts corresponding to targetNetworks configured in xchange.config.ts
 * @param config - The config settings, including extra wagmi configuration
 * @param config.contractName - deployed contract name
 * @param config.functionName - name of the function to be called
 * @param config.args - args to be passed to the function call
 */
export const useWagmiReadContract = <
  TContractName extends ContractName,
  TFunctionName extends ExtractAbiFunctionNames<
    ContractAbi<TContractName>,
    "pure" | "view"
  >,
>({
  contractName,
  functionName,
  args,
  ...readConfig
}: UseReadConfig<TContractName, TFunctionName>) => {
  const { data: deployedContract } = useDeployedContractInfo(contractName)
  const { targetNetwork } = useTargetNetwork()
  const { query: queryOptions, watch, ...readContractConfig } = readConfig
  // set watch to true by default
  const defaultWatch = watch ?? true

  const readContractHookRes = useWagmiReadContract({
    chainId: targetNetwork.id,
    functionName,
    address: deployedContract?.address,
    abi: deployedContract?.abi,
    args,
    ...(readContractConfig as any),
    query: {
      enabled: !Array.isArray(args) || !args.some(arg => arg === undefined),
      ...queryOptions,
    },
  }) as Omit<ReturnType<typeof useReadContract>, "data" | "refetch"> & {
    data: AbiFunctionReturnType<ContractAbi, TFunctionName> | undefined
    refetch: (
      options?: RefetchOptions | undefined
    ) => Promise<
      QueryObserverResult<
        AbiFunctionReturnType<ContractAbi, TFunctionName>,
        ReadContractErrorType
      >
    >
  }

  const queryClient = useQueryClient()
  const { data: blockNumber } = useBlockNumber({
    watch: defaultWatch,
    chainId: targetNetwork.id,
    query: {
      enabled: defaultWatch,
    },
  })

  useEffect(() => {
    if (defaultWatch) {
      queryClient.invalidateQueries({ queryKey: readContractHookRes.queryKey })
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [blockNumber])

  return readContractHookRes
}
