"use client";

import { useState, useEffect, useCallback } from "react";
import Image from "next/image";
import { Button } from "@heroui/react";
import { useApp } from "@/contexts/AppContext";
import { buttonStyles } from "@/lib/buttonStyles";
import { useAccount, useReadContract, useGasPrice } from 'wagmi';
import { formatUnits, parseUnits } from 'viem';
import { useTokenBalance } from '@/hooks/useBalance';
import { useSwap } from '@/hooks/useSwap';
import { abis, getContractAddress } from '@/lib/contracts';
import { useTokenDecimalsFromAddress } from '@/hooks/useTokenDecimals';
import Toast from "@/components/common/Toast";
import TokenSelector from '@/components/common/TokenSelector';
import { Token } from '@/lib/api/tokens';

interface TradePanelProps {
  showHeader?: boolean;
  title?: string;
  subtitle?: string;
}

export default function TradePanel({
  showHeader = false,
  title = "",
  subtitle = "",
}: TradePanelProps) {
  const { t } = useApp();
  const [sellAmount, setSellAmount] = useState<string>("");
  const [buyAmount, setBuyAmount] = useState<string>("");
  const [mounted, setMounted] = useState(false);
  const [tokenIn, setTokenIn] = useState<string>('');
  const [tokenInObj, setTokenInObj] = useState<Token | undefined>();
  const [tokenOut, setTokenOut] = useState<string>('');
  const [tokenOutObj, setTokenOutObj] = useState<Token | undefined>();
  const [toast, setToast] = useState<{ message: string; type: "success" | "error" | "info" | "warning" } | null>(null);
  const [slippage, setSlippage] = useState<number>(0.5);
  const SLIPPAGE_OPTIONS = [0.3, 0.5, 1, 3];

  useEffect(() => {
    setMounted(true);
  }, []);

  const { address, isConnected, chainId } = useAccount();

  // 从合约地址读取精度（tokenIn / tokenOut）
  const sellInputDecimals = useTokenDecimalsFromAddress(
    tokenInObj?.contractAddress,
    tokenInObj?.decimals ?? 18
  );
  const buyInputDecimals = useTokenDecimalsFromAddress(
    tokenOutObj?.contractAddress,
    tokenOutObj?.decimals ?? 18
  );
  const sellDisplayDecimals = Math.min(sellInputDecimals, 6);
  const truncateDecimals = (s: string, d: number) => { const p = s.split('.'); return p.length > 1 ? `${p[0]}.${p[1].slice(0, d)}` : s; };
  const isValidSellAmount = (v: string) => v !== '' && !isNaN(parseFloat(v)) && parseFloat(v) > 0;

  const handleSellAmountChange = (value: string) => {
    if (value === '') { setSellAmount(value); return; }
    if (!/^\d*\.?\d*$/.test(value)) return;
    const parts = value.split('.');
    if (parts.length > 1 && parts[1].length > sellDisplayDecimals) return;
    const maxBalance = truncateDecimals(tokenInBalance, sellDisplayDecimals);
    if (parseFloat(value) > parseFloat(maxBalance)) { setSellAmount(maxBalance); return; }
    setSellAmount(value);
  };

  // 余额：通过合约地址动态查询
  const { formattedBalance: tokenInBalance, isLoading: isBalanceLoading, refetch: refetchTokenIn } = useTokenBalance(
    tokenInObj?.contractAddress,
    sellInputDecimals
  );
  const { formattedBalance: tokenOutBalance, refetch: refetchTokenOut } = useTokenBalance(
    tokenOutObj?.contractAddress,
    buyInputDecimals
  );

  // 查询池子流动性：YTVault.usdyAmounts(tokenOutAddress)
  const vaultAddress = chainId ? getContractAddress('YTVault', chainId) : undefined;
  const tokenInAddress = tokenInObj?.contractAddress;
  const tokenOutAddress = tokenOutObj?.contractAddress;

  const { data: poolLiquidityRaw, refetch: refetchPool } = useReadContract({
    address: vaultAddress,
    abi: abis.YTVault,
    functionName: 'usdyAmounts',
    args: tokenOutAddress ? [tokenOutAddress as `0x${string}`] : undefined,
    query: {
      enabled: !!vaultAddress && !!tokenOutAddress,
    }
  });
  const poolLiquidityOut = poolLiquidityRaw ? formatUnits(poolLiquidityRaw as bigint, buyInputDecimals) : '0';

  // 查询实际兑换数量：getSwapAmountOut(tokenIn, tokenOut, amountIn)
  const sellAmountWei = (() => {
    if (!sellAmount || !isValidSellAmount(sellAmount)) return undefined;
    try { return parseUnits(sellAmount, sellInputDecimals); } catch { return undefined; }
  })();
  const { data: swapAmountOutRaw } = useReadContract({
    address: vaultAddress,
    abi: abis.YTVault,
    functionName: 'getSwapAmountOut',
    args: tokenInAddress && tokenOutAddress && sellAmountWei !== undefined
      ? [tokenInAddress as `0x${string}`, tokenOutAddress as `0x${string}`, sellAmountWei]
      : undefined,
    query: {
      enabled: !!vaultAddress && !!tokenInAddress && !!tokenOutAddress && sellAmountWei !== undefined && tokenIn !== tokenOut,
    },
  });
  // 返回 [amountOut, amountOutAfterFees, feeBasisPoints]
  const swapRaw = swapAmountOutRaw as [bigint, bigint, bigint] | undefined;
  const swapAmountOut = swapRaw ? formatUnits(swapRaw[1], buyInputDecimals) : '';
  const swapFeeBps = swapRaw ? Number(swapRaw[2]) : 0;

  // 读取 vault 基础 swap fee (bps)
  const { data: baseFeeRaw } = useReadContract({
    address: vaultAddress,
    abi: abis.YTVault,
    functionName: 'swapFeeBasisPoints',
    query: { enabled: !!vaultAddress },
  });
  const baseBps = baseFeeRaw ? Number(baseFeeRaw as bigint) : 0;

  // Gas price for network cost estimate
  const { data: gasPriceWei } = useGasPrice({ chainId });
  const GAS_ESTIMATE = 500_000n;
  const networkCostWei = gasPriceWei ? GAS_ESTIMATE * gasPriceWei : 0n;
  const networkCostNative = networkCostWei > 0n ? parseFloat(formatUnits(networkCostWei, 18)) : 0;
  const nativeToken = chainId === 97 ? 'BNB' : 'ETH';

  // Fee & Price Impact 计算
  const feeAmountBigInt = swapRaw ? swapRaw[0] - swapRaw[1] : 0n;
  const feeAmountFormatted = feeAmountBigInt > 0n ? truncateDecimals(formatUnits(feeAmountBigInt, buyInputDecimals), 6) : '0';
  const feePercent = swapFeeBps / 100;
  const impactBps = Math.max(0, swapFeeBps - baseBps);
  const impactPercent = impactBps / 100;

  const {
    status: swapStatus,
    error: swapError,
    isLoading: isSwapLoading,
    executeApproveAndSwap,
    reset: resetSwap,
  } = useSwap();

  // 买入数量由合约 getSwapAmountOut 决定
  useEffect(() => {
    if (swapAmountOut && isValidSellAmount(sellAmount)) {
      setBuyAmount(truncateDecimals(swapAmountOut, 6));
    } else {
      setBuyAmount("");
    }
  }, [swapAmountOut, sellAmount]);

  // 交易成功后刷新余额
  useEffect(() => {
    if (swapStatus === 'success') {
      setToast({ message: `${t('swap.successMsg')} ${tokenIn} ${t('swap.to')} ${tokenOut}!`, type: "success" });
      refetchTokenIn();
      refetchTokenOut();
      refetchPool();
      setTimeout(() => {
        resetSwap();
        setSellAmount("");
        setBuyAmount("");
      }, 3000);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [swapStatus]);

  // 显示错误提示
  useEffect(() => {
    if (swapError) {
      setToast({ message: swapError, type: swapError === 'Transaction cancelled' ? "warning" : "error" });
      refetchTokenIn();
      refetchTokenOut();
      refetchPool();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [swapError]);

  // 处理 tokenIn 选择
  const handleTokenInSelect = useCallback((token: Token) => {
    if (tokenInObj && token.symbol === tokenIn) return;
    if (token.symbol === tokenOut) {
      setTokenOut(tokenIn);
      setTokenOutObj(tokenInObj);
    }
    setTokenInObj(token);
    setTokenIn(token.symbol);
    setSellAmount("");
    setBuyAmount("");
  }, [tokenIn, tokenOut, tokenInObj]);

  // 处理 tokenOut 选择
  const handleTokenOutSelect = useCallback((token: Token) => {
    if (tokenOutObj && token.symbol === tokenOut) return;
    if (token.symbol === tokenIn) {
      setTokenIn(tokenOut);
      setTokenInObj(tokenOutObj);
    }
    setTokenOutObj(token);
    setTokenOut(token.symbol);
    setSellAmount("");
    setBuyAmount("");
  }, [tokenIn, tokenOut, tokenOutObj]);

  // 切换交易方向
  const handleSwapDirection = () => {
    const tempSymbol = tokenIn;
    const tempObj = tokenInObj;
    setTokenIn(tokenOut);
    setTokenInObj(tokenOutObj);
    setTokenOut(tempSymbol);
    setTokenOutObj(tempObj);
    setSellAmount("");
    setBuyAmount("");
  };

  // 百分比按钮处理
  const handlePercentage = (percentage: number) => {
    const balance = parseFloat(tokenInBalance);
    if (balance > 0) {
      const raw = (balance * percentage / 100).toString();
      setSellAmount(truncateDecimals(raw, sellDisplayDecimals));
    }
  };

  return (
    <div className={`flex flex-col gap-6 ${showHeader ? "w-full md:w-full md:max-w-[600px]" : "w-full"}`}>
      {/* Header Section - Optional */}
      {showHeader && (
        <div className="flex flex-col gap-2">
          <h1 className="text-heading-h2 font-bold text-text-primary dark:text-white text-center">
            {title}
          </h1>
          <p className="text-body-default font-medium text-text-secondary dark:text-gray-400 text-center">
            {subtitle}
          </p>
        </div>
      )}

      {/* Trade Panel */}
      <div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 p-6">
        <div className="flex flex-col gap-4">
          {/* SELL and BUY Container with Exchange Icon */}
          <div className="flex flex-col gap-2 relative">
            {/* SELL Section */}
            <div className="bg-bg-subtle dark:bg-gray-700 rounded-2xl p-4 flex flex-col gap-4">
              {/* Label and Buttons */}
              <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
                <span className="text-body-small font-bold text-text-secondary dark:text-gray-300">
                  {t("alp.sell")}
                </span>
                <div className="flex items-center gap-1.5">
                  {[25, 50, 75].map(pct => (
                    <button
                      key={pct}
                      onClick={() => handlePercentage(pct)}
                      className="flex-1 sm:flex-none bg-[#e5e7eb] dark:bg-gray-600 rounded-full px-2 sm:px-3 h-[22px] text-[10px] font-medium text-text-primary dark:text-white border-none hover:bg-[#d1d5db] dark:hover:bg-gray-500 transition-colors"
                    >
                      {pct}%
                    </button>
                  ))}
                  <button
                    onClick={() => handlePercentage(100)}
                    className="flex-1 sm:flex-none bg-[#e5e7eb] dark:bg-gray-600 rounded-full px-2 sm:px-3 h-[22px] text-[10px] font-medium text-text-primary dark:text-white border-none hover:bg-[#d1d5db] dark:hover:bg-gray-500 transition-colors"
                  >
                    {t("mintSwap.max")}
                  </button>
                </div>
              </div>

              {/* Input Row */}
              <div className="flex items-center justify-between gap-2 min-h-[60px] md:h-[70px]">
                <div className="flex flex-col items-start justify-between flex-1 h-full">
                  <input
                    type="text" inputMode="decimal"
                    placeholder="0.00"
                    value={sellAmount}
                    onChange={(e) => handleSellAmountChange(e.target.value)}
                    className="w-full text-left text-2xl md:text-[32px] font-bold leading-[130%] tracking-[-0.01em] text-text-primary dark:text-white placeholder:text-[#d1d5db] dark:placeholder:text-gray-500 bg-transparent border-none outline-none"
                  />
                  <span className="text-body-small font-medium text-text-tertiary dark:text-gray-400">
                    {sellAmount ? `≈ $${sellAmount}` : '--'}
                  </span>
                </div>
                <div className="flex flex-col items-end justify-between gap-1 h-full">
                  <TokenSelector
                    selectedToken={tokenInObj}
                    onSelect={handleTokenInSelect}
                    filterTypes={['stablecoin', 'yield-token']}
                    defaultSymbol="YT-A"
                  />
                  <span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-400">
                    {!mounted ? `0 ${tokenIn}` : (isBalanceLoading ? '...' : `${parseFloat(truncateDecimals(tokenInBalance, sellDisplayDecimals)).toLocaleString('en-US', { maximumFractionDigits: sellDisplayDecimals })} ${tokenIn}`)}
                  </span>
                </div>
              </div>
            </div>

            {/* Exchange Icon */}
            <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10">
              <button
                onClick={handleSwapDirection}
                className="bg-bg-surface dark:bg-gray-700 rounded-full w-10 h-10 flex items-center justify-center hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors cursor-pointer"
                style={{
                  boxShadow: "0px 1px 2px -1px rgba(0, 0, 0, 0.1), 0px 1px 3px 0px rgba(0, 0, 0, 0.1)",
                }}
              >
                <Image
                  src="/components/common/icon-swap-diagonal.svg"
                  alt="Exchange"
                  width={18}
                  height={18}
                />
              </button>
            </div>

            {/* BUY Section */}
            <div className="bg-bg-subtle dark:bg-gray-700 rounded-2xl p-4 flex flex-col gap-4">
              {/* Label */}
              <div className="flex flex-col gap-1">
                <div className="flex items-center justify-between">
                  <span className="text-body-small font-bold text-text-secondary dark:text-gray-300">
                    {t("alp.buy")}
                  </span>
                  <div className="flex items-center gap-1">
                    <Image src="/icons/ui/wallet-icon.svg" alt="" width={12} height={12} />
                    <span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-400">
                      {!mounted ? `0 ${tokenOut}` : `${parseFloat(tokenOutBalance).toLocaleString()} ${tokenOut}`}
                    </span>
                  </div>
                </div>
                <div className="flex items-center justify-end gap-1">
                  <span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-500">
                    {t('swap.pool')}: {!mounted ? '...' : `${parseFloat(poolLiquidityOut).toLocaleString()} ${tokenOut}`}
                  </span>
                </div>
              </div>

              {/* Input Row */}
              <div className="flex items-center justify-between gap-2 min-h-[60px] md:h-[70px]">
                <div className="flex flex-col items-start justify-between flex-1 h-full">
                  <input
                    type="text"
                    placeholder="0.00"
                    value={buyAmount}
                    readOnly
                    className="w-full text-left text-2xl md:text-[32px] font-bold leading-[130%] tracking-[-0.01em] text-text-primary dark:text-white placeholder:text-[#d1d5db] dark:placeholder:text-gray-500 bg-transparent border-none outline-none cursor-default"
                  />
                  <span className="text-body-small font-medium text-text-tertiary dark:text-gray-400">
                    {buyAmount ? `≈ $${buyAmount}` : '--'}
                  </span>
                </div>
                <div className="flex flex-col items-end justify-between gap-1 h-full">
                  <TokenSelector
                    selectedToken={tokenOutObj}
                    onSelect={handleTokenOutSelect}
                    filterTypes={['stablecoin', 'yield-token']}
                    defaultSymbol="YT-B"
                  />
                </div>
              </div>
            </div>
          </div>


          {/* Slippage Tolerance */}
          <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between px-1">
            <span className="text-body-small font-medium text-text-secondary dark:text-gray-400">
              {t("swap.slippageTolerance")}
            </span>
            <div className="flex items-center gap-1">
              {SLIPPAGE_OPTIONS.map((opt) => (
                <button
                  key={opt}
                  onClick={() => setSlippage(opt)}
                  className={`flex-1 sm:flex-none px-2 sm:px-3 h-7 rounded-full text-[12px] font-semibold transition-colors ${
                    slippage === opt
                      ? "bg-foreground text-background"
                      : "bg-[#e5e7eb] dark:bg-gray-600 text-text-primary dark:text-white hover:bg-[#d1d5db] dark:hover:bg-gray-500"
                  }`}
                >
                  {opt}%
                </button>
              ))}
            </div>
          </div>

          {/* Submit Button */}
          {(() => {
            const inputAmt = parseFloat(sellAmount) || 0;
            const balance  = parseFloat(tokenInBalance) || 0;
            const poolAmt  = parseFloat(poolLiquidityOut) || 0;
            const insufficientBalance = inputAmt > 0 && inputAmt > balance;
            const insufficientPool = inputAmt > 0 && poolAmt > 0 && inputAmt > poolAmt;
            const buttonDisabled = !mounted || !isConnected || !isValidSellAmount(sellAmount) || isSwapLoading || tokenIn === tokenOut || insufficientBalance || insufficientPool || !tokenInObj || !tokenOutObj;
            const buttonLabel = (() => {
              if (!mounted || !isConnected) return t('common.connectWallet');
              if (swapStatus === 'idle' && !!sellAmount && !isValidSellAmount(sellAmount)) return t('common.invalidAmount');
              if (insufficientBalance) return t('supply.insufficientBalance');
              if (insufficientPool) return t('swap.insufficientLiquidity');
              if (swapStatus === 'approving') return t('common.approving');
              if (swapStatus === 'approved') return t('swap.approved');
              if (swapStatus === 'swapping') return t('swap.swapping');
              if (swapStatus === 'success') return t('common.success');
              if (swapStatus === 'error') return t('common.failed');
              return `${t('swap.swapBtn')} ${tokenIn} ${t('swap.to')} ${tokenOut}`;
            })();
            const minOut = swapAmountOut && isValidSellAmount(sellAmount)
              ? (parseFloat(swapAmountOut) * (1 - slippage / 100)).toFixed(buyInputDecimals)
              : '0';
            return (
              <Button
                isDisabled={buttonDisabled}
                color="default"
                className={buttonStyles({ intent: "theme" })}
                onPress={() => {
                  if (!insufficientBalance && !insufficientPool && isValidSellAmount(sellAmount) && tokenIn !== tokenOut && tokenInObj && tokenOutObj) {
                    setToast(null);
                    resetSwap();
                    executeApproveAndSwap(
                      tokenInObj.contractAddress,
                      sellInputDecimals,
                      tokenOutObj.contractAddress,
                      buyInputDecimals,
                      sellAmount,
                      minOut
                    );
                  }
                }}
              >
                {buttonLabel}
              </Button>
            );
          })()}

          {/* Rate & Info Section */}
          <div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 px-4 py-3 flex flex-col gap-2">
            {/* Exchange Rate */}
            <div className="flex items-center justify-between">
              <span className="text-body-small font-medium text-text-secondary dark:text-gray-300">
                {swapAmountOut && isValidSellAmount(sellAmount)
                  ? `1 ${tokenIn} ≈ ${truncateDecimals((parseFloat(swapAmountOut) / parseFloat(sellAmount)).toString(), 6)} ${tokenOut}`
                  : `1 ${tokenIn} = -- ${tokenOut}`}
              </span>
            </div>
            {/* Divider */}
            <div className="border-t border-border-gray dark:border-gray-600" />
            {/* Network Cost */}
            <div className="flex items-center justify-between">
              <span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">{t('swap.networkCost')}</span>
              <span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300">
                {networkCostNative > 0 ? `~${networkCostNative.toFixed(6)} ${nativeToken}` : '--'}
              </span>
            </div>
            {/* Max Slippage */}
            <div className="flex items-center justify-between">
              <span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">{t('swap.maxSlippage')}</span>
              <span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300">{slippage}%</span>
            </div>
            {/* Price Impact */}
            <div className="flex items-center justify-between">
              <span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">{t('swap.priceImpact')}</span>
              <span className={`text-caption-tiny font-medium ${
                isValidSellAmount(sellAmount) && swapAmountOut
                  ? impactPercent > 1 ? 'text-red-500' : impactPercent > 0.3 ? 'text-amber-500' : 'text-text-secondary dark:text-gray-300'
                  : 'text-text-secondary dark:text-gray-300'
              }`}>
                {isValidSellAmount(sellAmount) && swapAmountOut ? `${impactPercent.toFixed(2)}%` : '--'}
              </span>
            </div>
            {/* Fee */}
            <div className="flex items-center justify-between">
              <span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">{t('swap.fee')}</span>
              <span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300">
                {swapFeeBps > 0 && isValidSellAmount(sellAmount) && swapAmountOut
                  ? `${feePercent.toFixed(2)}% (≈${feeAmountFormatted} ${tokenOut})`
                  : '--'}
              </span>
            </div>
          </div>
        </div>
      </div>

      {/* Toast Notification */}
      {toast && (
        <Toast
          message={toast.message}
          type={toast.type}
          isOpen={!!toast}
          onClose={() => setToast(null)}
        />
      )}
    </div>
  );
}
