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

type WithdrawStatus = 'idle' | 'withdrawing' | 'success' | 'error'

export function useLendingWithdraw() {
  const { address, chainId } = useAccount()
  const { bySymbol } = useTokenList()
  const usdcToken = bySymbol['USDC']
  const [status, setStatus] = useState<WithdrawStatus>('idle')
  const [error, setError] = useState<string | null>(null)

  const {
    writeContractAsync: withdrawWrite,
    data: withdrawHash,
    isPending: isWithdrawPending,
    reset: resetWithdraw,
  } = useWriteContract()

  const {
    isLoading: isWithdrawConfirming,
    isSuccess: isWithdrawSuccess,
    isError: isWithdrawError,
    error: withdrawReceiptError,
  } = useWaitForTransactionReceipt({ hash: withdrawHash })

  const executeWithdraw = useCallback(async (amount: string) => {
    if (status !== 'idle') return false
    if (!address || !chainId || !usdcToken || !amount) {
      setError('Missing required parameters')
      return false
    }
    if (!isValidAmount(amount)) {
      setError('Invalid amount')
      return false
    }

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

      const lendingProxyAddress = getContractAddress('lendingProxy', chainId)
      if (!lendingProxyAddress) {
        throw new Error('Contract not deployed on this chain')
      }

      const usdcDecimals = usdcToken.onChainDecimals ?? usdcToken.decimals
      const amountInWei = parseUnits(amount, usdcDecimals)

      await withdrawWrite({
        address: lendingProxyAddress,
        abi: abis.lendingProxy,
        functionName: 'withdraw',
        args: [amountInWei],
        gas: WITHDRAW_GAS_LIMIT,
      })

      return true
    } catch (err: unknown) {
      handleContractCatchError(err, 'Withdraw failed', setError, setStatus as (s: string) => void)
      return false
    }
  }, [address, chainId, withdrawWrite, usdcToken, status])

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

  useEffect(() => {
    if (isWithdrawError && status === 'withdrawing') {
      setError(parseContractError(withdrawReceiptError))
      setStatus('error')
    }
  }, [isWithdrawError, status, withdrawReceiptError])

  const reset = useCallback(() => {
    setStatus('idle')
    setError(null)
    resetWithdraw()
  }, [resetWithdraw])

  return {
    status,
    error,
    isLoading: isWithdrawPending || isWithdrawConfirming,
    withdrawHash,
    executeWithdraw,
    reset,
  }
}
