import { useAccount, useReadContract, useReadContracts } from 'wagmi'
import { formatUnits } from 'viem'
import { abis, getContractAddress } from '@/lib/contracts'
import { useEffect, useState } from 'react'
import { Token } from '@/lib/api/tokens'
import { useTokenList } from './useTokenList'

/**
 * 健康因子状态
 */
export type HealthFactorStatus = 'safe' | 'warning' | 'danger' | 'critical'

/**
 * 健康因子结果
 */
export interface HealthFactorResult {
  healthFactor: bigint
  formattedHealthFactor: string
  status: HealthFactorStatus
  utilization: number // 利用率百分比
  borrowValue: bigint // 借款价值（USD，1e18精度）
  collateralValue: bigint // 抵押品价值（USD，1e18精度）
  isLoading: boolean
  refetch: () => void
}

/**
 * 获取用户健康因子
 *
 * 健康因子定义：
 * - > 1.5: 安全（绿色）
 * - 1.2 ~ 1.5: 警告（黄色）
 * - 1.0 ~ 1.2: 危险（橙色）
 * - < 1.0: 临界/可被清算（红色）
 * - MaxUint256: 无债务
 */
export function useHealthFactor(): HealthFactorResult {
  const { address, chainId } = useAccount()
  const { bySymbol } = useTokenList()
  const usdcToken = bySymbol['USDC']
  const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined

  // 1. 获取用户基本信息（principal）
  const { data: userBasic, refetch: refetchUserBasic } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'userBasic',
    args: address ? [address] : undefined,
    query: {
      enabled: !!address && !!lendingProxyAddress,
    },
  })

  const principal = userBasic !== undefined ? (userBasic as bigint) : 0n

  // 如果没有借款（principal >= 0），提前返回
  const hasDebt = principal < 0n
  const shouldCalculate = hasDebt && !!address && !!lendingProxyAddress

  // 2. 获取借款索引
  const { data: borrowIndex, refetch: refetchBorrowIndex } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'borrowIndex',
    query: {
      enabled: shouldCalculate,
    },
  })

  // 3. 获取价格预言机地址
  const { data: priceFeedAddress } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'lendingPriceSource',
    query: {
      enabled: shouldCalculate,
    },
  })

  // 4. 获取 baseToken 地址
  const { data: baseToken } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'baseToken',
    query: {
      enabled: shouldCalculate,
    },
  })

  // 5. 直接获取资产列表（YT-A, YT-B, YT-C）
  const assetIndices = [0, 1, 2] as const

  const assetListContracts = assetIndices.map((i) => ({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'assetList' as const,
    args: [BigInt(i)],
  }))

  const { data: assetListData } = useReadContracts({
    contracts: assetListContracts as any,
    query: {
      enabled: shouldCalculate && assetListContracts.length > 0,
    },
  })

  const assetList = assetListData?.map((item) => item.result as `0x${string}`).filter(Boolean) || []

  // 7. 使用 useState 来管理计算结果
  const [result, setResult] = useState<HealthFactorResult>({
    healthFactor: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), // MaxUint256
    formattedHealthFactor: '∞',
    status: 'safe',
    utilization: 0,
    borrowValue: 0n,
    collateralValue: 0n,
    isLoading: true,
    refetch: () => {
      refetchUserBasic()
      refetchBorrowIndex()
      refetchCollateral()
      refetchPrices()
    },
  })

  // 8. 获取所有抵押品余额和配置
  const collateralContracts = assetList.flatMap((asset) => [
    // 获取用户抵押品余额
    {
      address: lendingProxyAddress,
      abi: abis.lendingProxy,
      functionName: 'userCollateral' as const,
      args: [address, asset],
    },
    // 获取资产配置
    {
      address: lendingProxyAddress,
      abi: abis.lendingProxy,
      functionName: 'assetConfigs' as const,
      args: [asset],
    },
  ])

  const { data: collateralData, refetch: refetchCollateral } = useReadContracts({
    contracts: collateralContracts as any,
    query: {
      enabled: shouldCalculate && assetList.length > 0,
    },
  })

  // 9. 获取所有资产价格（包括 baseToken）
  const priceContracts = [baseToken, ...assetList].filter(Boolean).map((token) => ({
    address: priceFeedAddress,
    abi: [
      {
        type: 'function',
        name: 'getPrice',
        inputs: [{ name: 'asset', type: 'address' }],
        outputs: [{ name: '', type: 'uint256' }],
        stateMutability: 'view',
      },
    ],
    functionName: 'getPrice' as const,
    args: [token],
  }))

  const { data: priceData, refetch: refetchPrices } = useReadContracts({
    contracts: priceContracts as any,
    query: {
      enabled: shouldCalculate && !!priceFeedAddress && priceContracts.length > 0,
    },
  })

  // 10. 计算健康因子
  useEffect(() => {
    if (!shouldCalculate) {
      // 没有债务，返回最大健康因子
      setResult({
        healthFactor: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
        formattedHealthFactor: '∞',
        status: 'safe',
        utilization: 0,
        borrowValue: 0n,
        collateralValue: 0n,
        isLoading: false,
        refetch: () => {
          refetchUserBasic()
        },
      })
      return
    }

    if (!borrowIndex || !priceData || !collateralData || !baseToken || !chainId) {
      return
    }

    try {
      // 计算实际债务（principal * borrowIndex / 1e18）
      const balance = (principal * (borrowIndex as bigint)) / BigInt(1e18)
      const debt = -balance // 转为正数

      // 获取 baseToken 价格（第一个价格）
      const basePrice = priceData[0]?.result as bigint
      if (!basePrice) return

      // 计算债务价值（USD）
      const baseDecimals = usdcToken?.onChainDecimals ?? usdcToken?.decimals ?? 18
      const debtValue = (debt * basePrice) / BigInt(10 ** baseDecimals)

      if (debtValue === 0n) {
        setResult({
          healthFactor: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
          formattedHealthFactor: '∞',
          status: 'safe',
          utilization: 0,
          borrowValue: 0n,
          collateralValue: 0n,
          isLoading: false,
          refetch: () => {
            refetchUserBasic()
          },
        })
        return
      }

      // 计算抵押品总价值（使用 liquidateCollateralFactor）
      let totalCollateralValue = 0n

      // assetConfigs 返回元组: [asset, decimals, borrowCollateralFactor, liquidateCollateralFactor, liquidationFactor, supplyCap]
      type AssetConfigTuple = readonly [string, number, bigint, bigint, bigint, bigint]

      for (let i = 0; i < assetList.length; i++) {
        const collateralAmount = collateralData[i * 2]?.result as bigint
        const assetConfig = collateralData[i * 2 + 1]?.result as AssetConfigTuple | undefined
        const assetPrice = priceData[i + 1]?.result as bigint

        if (collateralAmount > 0n && assetConfig && assetPrice) {
          // assetConfig[1] = decimals, assetConfig[3] = liquidateCollateralFactor
          const assetScale = 10n ** BigInt(Number(assetConfig[1]))
          const collateralValue = (collateralAmount * assetPrice) / assetScale

          // 应用清算折扣系数（liquidateCollateralFactor）
          const discountedValue = (collateralValue * assetConfig[3]) / BigInt(1e18)
          totalCollateralValue += discountedValue
        }
      }

      // 计算健康因子 = 抵押品价值 / 债务价值（1e18 精度）
      const healthFactor = (totalCollateralValue * BigInt(1e18)) / debtValue

      // 计算利用率（债务/抵押品）
      const utilization = totalCollateralValue > 0n
        ? Number((debtValue * BigInt(10000)) / totalCollateralValue) / 100
        : 0

      // 确定健康因子状态
      let status: HealthFactorStatus
      const hfNumber = Number(formatUnits(healthFactor, 18))
      if (hfNumber >= 1.5) {
        status = 'safe'
      } else if (hfNumber >= 1.2) {
        status = 'warning'
      } else if (hfNumber >= 1.0) {
        status = 'danger'
      } else {
        status = 'critical'
      }

      // 格式化健康因子显示
      const formattedHealthFactor = hfNumber >= 10
        ? hfNumber.toFixed(1)
        : hfNumber >= 1
        ? hfNumber.toFixed(2)
        : hfNumber.toFixed(3)

      setResult({
        healthFactor,
        formattedHealthFactor,
        status,
        utilization,
        borrowValue: debtValue,
        collateralValue: totalCollateralValue,
        isLoading: false,
        refetch: () => {
          refetchUserBasic()
          refetchBorrowIndex()
          refetchCollateral()
          refetchPrices()
        },
      })
    } catch (error) {
      console.error('Health factor calculation error:', error)
      setResult((prev) => ({ ...prev, isLoading: false }))
    }
  }, [
    shouldCalculate,
    principal,
    borrowIndex,
    priceData,
    collateralData,
    baseToken,
    chainId,
    assetList.length,
    refetchUserBasic,
  ])

  return result
}

/**
 * 获取用户借款余额
 */
export function useBorrowBalance() {
  const { address, chainId } = useAccount()
  const { bySymbol } = useTokenList()
  const usdcToken = bySymbol['USDC']
  const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined

  const { data: borrowBalance, refetch } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'borrowBalanceOf',
    args: address ? [address] : undefined,
    query: {
      enabled: !!address && !!lendingProxyAddress,
    },
  })

  const usdcDecimals = usdcToken?.onChainDecimals ?? usdcToken?.decimals ?? 18
  const formattedBalance = borrowBalance ? formatUnits(borrowBalance as bigint, usdcDecimals) : '0.00'

  return {
    balance: borrowBalance as bigint | undefined,
    formattedBalance,
    refetch,
  }
}

/**
 * 获取用户在特定资产的抵押品余额
 */
export function useCollateralBalance(token: Token | undefined) {
  const { address, chainId } = useAccount()
  const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined

  const { data: collateralBalance, refetch } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'userCollateral',
    args: address && token?.contractAddress ? [address, token.contractAddress as `0x${string}`] : undefined,
    query: {
      enabled: !!address && !!lendingProxyAddress && !!token?.contractAddress,
    },
  })

  const decimals = token?.onChainDecimals ?? token?.decimals ?? 18
  const formattedBalance = collateralBalance ? formatUnits(collateralBalance as bigint, decimals) : '0.00'

  return {
    balance: collateralBalance as bigint | undefined,
    formattedBalance,
    refetch,
  }
}

/**
 * 获取协议利用率
 */
export function useProtocolUtilization() {
  const { chainId } = useAccount()
  const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined

  const { data: utilization } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'getUtilization',
    query: {
      enabled: !!lendingProxyAddress,
    },
  })

  // utilization 是 1e18 精度的百分比
  const utilizationPercent = utilization ? Number(formatUnits(utilization as bigint, 18)) * 100 : 0

  return {
    utilization: utilization as bigint | undefined,
    utilizationPercent,
  }
}

const SECONDS_PER_YEAR = 365 * 24 * 60 * 60

function calcAPY(annualAprBigint: bigint | undefined): { apr: number; apy: number } {
  if (!annualAprBigint) return { apr: 0, apy: 0 }
  // getSupplyRate / getBorrowRate return annual APR with 1e18 precision
  const annualApr = Number(formatUnits(annualAprBigint, 18)) // e.g. 0.05 = 5%
  const perSecondRate = annualApr / SECONDS_PER_YEAR
  const apy = perSecondRate > 0
    ? (Math.pow(1 + perSecondRate, SECONDS_PER_YEAR) - 1) * 100
    : 0
  return { apr: annualApr * 100, apy }
}

/**
 * 获取当前供应 APY
 * getSupplyRate() 返回年化 APR（1e18 精度，uint64）
 */
export function useSupplyAPY() {
  const { chainId } = useAccount()
  const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined

  const { data: supplyRate } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'getSupplyRate',
    query: { enabled: !!lendingProxyAddress },
  })

  const { apr, apy } = calcAPY(supplyRate as bigint | undefined)

  return {
    supplyRate: supplyRate as bigint | undefined,
    apr,
    apy,
  }
}

/**
 * 获取当前借款 APR/APY
 * getBorrowRate() 返回年化 APR（1e18 精度，uint64）
 */
export function useBorrowAPR() {
  const { chainId } = useAccount()
  const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined

  const { data: borrowRate } = useReadContract({
    address: lendingProxyAddress,
    abi: abis.lendingProxy,
    functionName: 'getBorrowRate',
    query: { enabled: !!lendingProxyAddress },
  })

  const { apr, apy } = calcAPY(borrowRate as bigint | undefined)

  return {
    borrowRate: borrowRate as bigint | undefined,
    apr,
    apy,
  }
}
