import { useEffect } from "react"
import { useAccount } from "wagmi"
import { readContract } from "@wagmi/core"

import { Address } from "@/components/shared/types"
import { baseWagmiConfig as wagmiConfig } from "@/wagmi"
import useStore from "../store"

type Nft = { address: Address; id: number }

const NFT_COLLECTION_ADDRESSES: Nft[] = [
  { address: "0xb2a56d514cd6dca0e4b9b2827868cb21330a0d09", id: 1 },
  { address: "0xb2a56d514cd6dca0e4b9b2827868cb21330a0d09", id: 2 },
]

const WHITELIST_ADDRESSES = new Set(
  [
    "0xab5c2f8a64c9ec2cb63a9de9e025fe0851bd059b",
    "0x1a7052ddc54130c3e7a9bef8100ce687b571fa43",
    "0xd870765964c1f2d5f45d9542881afa2afdfbd01a",
    "0x687f4304df62449dbc6c95fe9a8cb1153d40d42e",
    "0xacafd30551cf0222d68834cde5c4034589972cfb",
    "0x9b533e9442e01fbdd6e7ba17d1f1e101607703ba",
    "0xaff99d17bd1409bb007d2c67ccc25343ae22290a",
    "0x013e31d32F5c26F4901937B9Ad4E7C12E243F308",
    "0x40Bda839a3De78A1E72243DC745aE5AE5644181d",
  ].map((addr) => addr.toLowerCase()),
)

const abi = [
  {
    inputs: [
      { internalType: "address", name: "owner", type: "address" },
      { internalType: "uint256", name: "id", type: "uint256" },
    ],
    name: "balanceOf",
    outputs: [{ internalType: "uint256", name: "result", type: "uint256" }],
    stateMutability: "view",
    type: "function",
  },
] as const

const getBalance = async (eoa: Address, nft: Nft) => {
  try {
    const result = await readContract(wagmiConfig, {
      address: nft.address,
      abi,
      functionName: "balanceOf",
      args: [eoa, BigInt(nft.id)],
    })
    return Number(result)
  } catch (err) {
    console.error(err)
    return 0
  }
}

export default function useNftGating() {
  const { address, isConnected } = useAccount()
  const { hasNftData, setNftData } = useStore()

  useEffect(() => {
    if (!address || !isConnected) return

    if (WHITELIST_ADDRESSES.has(address.toLowerCase())) {
      setNftData(true)
      return
    }

    setNftData(false, true)
  }, [address, isConnected, setNftData])

  useEffect(() => {
    if (!address || !isConnected) return

    const fetchNftData = async () => {
      setNftData(false, true)
      try {
        for (const nft of NFT_COLLECTION_ADDRESSES) {
          const balance = await getBalance(address, nft)
          if (balance) {
            setNftData(true)
            return
          }
        }
        setNftData(false)
      } catch (error) {
        console.error("Error fetching NFT data:", error)
        setNftData(false)
      }
    }

    fetchNftData()
  }, [address, isConnected, setNftData])

  return { hasNftData }
}
