import { useState, useEffect } from 'react'
import { useAccount, useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
import { parseUnits } from 'viem'
import { abis, getContractAddress } from '@/lib/contracts'
import { handleContractCatchError, isValidAmount, parseContractError } from '@/lib/errors'
import { SWAP_GAS_LIMIT } from '@/lib/constants'

type DepositStatus = 'idle' | 'approving' | 'approved' | 'depositing' | 'success' | 'error'

/**
 * Hook for adding liquidity to YT Pool
 * Accepts token contract address and decimals directly — no hardcoded token symbols.
 */
export function usePoolDeposit() {
  const { address, chainId } = useAccount()
  const [status, setStatus] = useState<DepositStatus>('idle')
  const [error, setError] = useState<string | null>(null)
  const [approveHash, setApproveHash] = useState<`0x${string}` | undefined>()
  const [depositHash, setDepositHash] = useState<`0x${string}` | undefined>()

  const { writeContractAsync: approveWrite } = useWriteContract()
  const { writeContractAsync: depositWrite } = useWriteContract()

  const { isLoading: isApproving, isSuccess: isApproveSuccess, isError: isApproveError, error: approveReceiptError } = useWaitForTransactionReceipt({
    hash: approveHash,
  })

  const { isLoading: isDepositing, isSuccess: isDepositSuccess, isError: isDepositError, error: depositReceiptError } = useWaitForTransactionReceipt({
    hash: depositHash,
  })

  const executeApprove = async (tokenAddress: string, tokenDecimals: number, amount: string) => {
    if (status !== 'idle') return false
    if (!chainId) {
      setError('Please connect your wallet')
      return false
    }
    if (!isValidAmount(amount)) {
      setError('Invalid amount')
      return false
    }

    try {
      setStatus('approving')
      setError(null)

      const rewardRouterAddress = getContractAddress('YTRewardRouter', chainId)

      if (!tokenAddress || !rewardRouterAddress) {
        throw new Error('Contract not deployed on this chain')
      }

      const amountInWei = parseUnits(amount, tokenDecimals)

      const hash = await approveWrite({
        address: tokenAddress as `0x${string}`,
        abi: abis.USDY,
        functionName: 'approve',
        args: [rewardRouterAddress, amountInWei],
      })

      setApproveHash(hash)
      return true
    } catch (err: unknown) {
      handleContractCatchError(err, 'Approval failed', setError, setStatus as (s: string) => void)
      return false
    }
  }

  const executeDeposit = async (
    tokenAddress: string,
    tokenDecimals: number,
    amount: string,
    minUsdy: string = '0',
    minYtLP: string = '0'
  ) => {
    if (status === 'depositing' || status === 'success' || status === 'error') return false
    if (!chainId) {
      setError('Please connect your wallet')
      return false
    }
    if (!isValidAmount(amount)) {
      setError('Invalid amount')
      return false
    }

    try {
      setStatus('depositing')
      setError(null)

      const rewardRouterAddress = getContractAddress('YTRewardRouter', chainId)

      if (!tokenAddress || !rewardRouterAddress) {
        throw new Error('Contract not deployed on this chain')
      }

      const amountInWei = parseUnits(amount, tokenDecimals)
      const minUsdyInWei = parseUnits(minUsdy, 18)
      const minYtLPInWei = parseUnits(minYtLP, 18)

      const hash = await depositWrite({
        address: rewardRouterAddress,
        abi: abis.YTRewardRouter,
        functionName: 'addLiquidity',
        args: [tokenAddress as `0x${string}`, amountInWei, minUsdyInWei, minYtLPInWei],
        gas: SWAP_GAS_LIMIT,
      })

      setDepositHash(hash)
      return true
    } catch (err: unknown) {
      handleContractCatchError(err, 'Transaction failed', setError, setStatus as (s: string) => void)
      return false
    }
  }

  const executeApproveAndDeposit = async (
    tokenAddress: string,
    tokenDecimals: number,
    amount: string,
    minUsdy: string = '0',
    minYtLP: string = '0'
  ) => {
    if (status !== 'idle') return
    const approved = await executeApprove(tokenAddress, tokenDecimals, amount)
    if (!approved) return

    await new Promise(resolve => setTimeout(resolve, 2000))

    await executeDeposit(tokenAddress, tokenDecimals, amount, minUsdy, minYtLP)
  }

  const reset = () => {
    setStatus('idle')
    setError(null)
    setApproveHash(undefined)
    setDepositHash(undefined)
  }

  useEffect(() => {
    if (isApproveSuccess && status === 'approving') {
      setStatus('approved')
    }
  }, [isApproveSuccess, status])

  useEffect(() => {
    if (isApproveError && status === 'approving') {
      setError(parseContractError(approveReceiptError))
      setStatus('error')
    }
  }, [isApproveError, status, approveReceiptError])

  useEffect(() => {
    if (isDepositSuccess && status === 'depositing') {
      setStatus('success')
    }
  }, [isDepositSuccess, status])

  useEffect(() => {
    if (isDepositError && status === 'depositing') {
      setError(parseContractError(depositReceiptError))
      setStatus('error')
    }
  }, [isDepositError, status, depositReceiptError])

  return {
    status,
    error,
    isLoading: isApproving || isDepositing,
    approveHash,
    depositHash,
    executeApprove,
    executeDeposit,
    executeApproveAndDeposit,
    reset,
  }
}
