'use client';

import { useState, useEffect, useRef, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { ArrowDownUp, ChevronDown, Settings, CheckCircle, XCircle, Loader2 } from 'lucide-react';
import { useAccount } from 'wagmi';
import { useTokenDetails, useGetPoolsByToken, type TokenDetails } from '@/hooks/usePartyPlanner';
import { useSwapAmounts, useSwap, selectBestSwapRoute, type ActualSwapAmounts } from '@/hooks/usePartyPool';
import { formatUnits, parseUnits } from 'viem';
import { SwapReviewModal } from './swap-review-modal';

type TransactionStatus = 'idle' | 'pending' | 'success' | 'error';

export function SwapForm() {
  const { t } = useTranslation();
  const { isConnected, address } = useAccount();
  const [fromAmount, setFromAmount] = useState('');
  const [toAmount, setToAmount] = useState('');
  const [selectedFromToken, setSelectedFromToken] = useState<TokenDetails | null>(null);
  const [selectedToToken, setSelectedToToken] = useState<TokenDetails | null>(null);
  const [isFromDropdownOpen, setIsFromDropdownOpen] = useState(false);
  const [isToDropdownOpen, setIsToDropdownOpen] = useState(false);
  const [maxSlippage, setMaxSlippage] = useState<string>('1'); // Default 1%
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
  const [isReviewModalOpen, setIsReviewModalOpen] = useState(false);
  const [transactionStatus, setTransactionStatus] = useState<TransactionStatus>('idle');
  const [transactionError, setTransactionError] = useState<string | null>(null);
  const [actualSwapAmounts, setActualSwapAmounts] = useState<ActualSwapAmounts | null>(null);
  const fromDropdownRef = useRef<HTMLDivElement>(null);
  const toDropdownRef = useRef<HTMLDivElement>(null);

  // Use the custom hook to get all token details with a single batched RPC call
  const { tokenDetails, loading } = useTokenDetails(address);

  // Get available tokens for the selected "from" token
  const { availableTokens, error: poolsError } = useGetPoolsByToken(selectedFromToken?.address);

  // Only calculate swap amounts when both tokens are selected
  // Use useMemo to prevent creating a new array reference on every render
  const filteredAvailableTokens = useMemo(() => {
    if (selectedFromToken && selectedToToken && availableTokens) {
      return availableTokens.filter(token =>
        token.address.toLowerCase() === selectedToToken.address.toLowerCase()
      );
    }
    return null;
  }, [selectedFromToken, selectedToToken, availableTokens]);

  // Get the current slippage value
  const currentSlippage = parseFloat(maxSlippage) || 1;

  // Calculate swap amounts for the selected token pair only
  const { swapAmounts } = useSwapAmounts(
    filteredAvailableTokens,
    fromAmount,
    selectedFromToken?.decimals || 18,
    currentSlippage
  );

  // Check if user has insufficient balance
  const hasInsufficientBalance = useMemo(() => {
    if (!selectedFromToken || !fromAmount || fromAmount === '') {
      return false;
    }
    try {
      const inputAmount = parseUnits(fromAmount, selectedFromToken.decimals);
      return inputAmount > selectedFromToken.balance;
    } catch {
      return false;
    }
  }, [selectedFromToken, fromAmount]);

  // Check if calculated slippage exceeds 5%
  const slippageExceedsLimit = useMemo(() => {
    if (!swapAmounts || swapAmounts.length === 0 || swapAmounts[0].calculatedSlippage === undefined) {
      return false;
    }
    return Math.abs(swapAmounts[0].calculatedSlippage) > 5;
  }, [swapAmounts]);

  // Initialize swap hook
  const { executeSwap, estimateGas, isSwapping, gasEstimate, isEstimatingGas } = useSwap();

  // Update "You Receive" amount when swap calculation completes
  useEffect(() => {
    if (hasInsufficientBalance) {
      setToAmount('');
      return;
    }
    if (swapAmounts && swapAmounts.length > 0 && selectedToToken) {
      const swapResult = swapAmounts[0]; // Get the first (and should be only) result
      const formattedAmount = formatUnits(swapResult.amountOut, selectedToToken.decimals);
      setToAmount(formattedAmount);
    }
  }, [swapAmounts, selectedToToken, hasInsufficientBalance]);

  // Close dropdowns when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (fromDropdownRef.current && !fromDropdownRef.current.contains(event.target as Node)) {
        setIsFromDropdownOpen(false);
      }
      if (toDropdownRef.current && !toDropdownRef.current.contains(event.target as Node)) {
        setIsToDropdownOpen(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  const handleSwap = async () => {
    if (!swapAmounts || swapAmounts.length === 0) {
      console.error('No swap amounts available');
      return;
    }

    if (!selectedFromToken || !selectedToToken) {
      console.error('Tokens not selected');
      return;
    }

    setTransactionStatus('pending');
    setTransactionError(null);

    try {
      // Use the shared helper to select the best swap route
      const bestRoute = selectBestSwapRoute(swapAmounts);

      if (!bestRoute) {
        console.error('No valid swap route found');
        setTransactionError('No valid swap route found');
        setTransactionStatus('error');
        return;
      }

      // Use the user's input directly as maxAmountIn
      const maxAmountIn = parseUnits(fromAmount, selectedFromToken.decimals);

      // Execute the swap and capture actual amounts from the transaction
      const result = await executeSwap(
        bestRoute.poolAddress,
        selectedFromToken.address,
        bestRoute.inputTokenIndex,
        bestRoute.outputTokenIndex,
        maxAmountIn,
        currentSlippage
      );

      // Store the actual swap amounts if available
      if (result?.actualSwapAmounts) {
        setActualSwapAmounts(result.actualSwapAmounts);
      }

      setTransactionStatus('success');
    } catch (err) {
      console.error('Swap failed:', err);
      setTransactionError(err instanceof Error ? err.message : 'Transaction failed');
      setTransactionStatus('error');
    }
  };

  const handleCloseModal = () => {
    if (transactionStatus === 'success') {
      // Clear the form after successful swap
      setFromAmount('');
      setToAmount('');
      setSelectedFromToken(null);
      setSelectedToToken(null);
    }
    setTransactionStatus('idle');
    setTransactionError(null);
  };

  const switchTokens = () => {
    // Switch both tokens and amounts
    const tempFromAmount = fromAmount;
    const tempFromToken = selectedFromToken;

    setFromAmount(toAmount);
    setToAmount(tempFromAmount);
    setSelectedFromToken(selectedToToken);
    setSelectedToToken(tempFromToken);
  };

  // Estimate gas when swap parameters change
  useEffect(() => {
    const estimateSwapGas = async () => {
      if (!swapAmounts || swapAmounts.length === 0 || !selectedFromToken || !selectedToToken || !fromAmount || !isConnected) {
        return;
      }

      await estimateGas();
    };

    estimateSwapGas();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [swapAmounts, selectedFromToken, selectedToToken, fromAmount, currentSlippage, isConnected]);

  return (
    <Card className="w-full max-w-md mx-auto relative">
      <CardHeader>
        <div className="flex justify-between items-center">
          <CardTitle>Swap</CardTitle>
          <Button
            variant="ghost"
            size="icon"
            onClick={() => setIsSettingsOpen(true)}
            className="h-8 w-8"
          >
            <Settings className="h-5 w-5" />
          </Button>
        </div>
      </CardHeader>
      <CardContent className="space-y-4">
        {/* From Token */}
        <div className="space-y-2">
          <div className="flex justify-between items-center text-sm">
            <label className="text-muted-foreground">{t('swap.youPay')}</label>
            <Button
              variant="ghost"
              size="sm"
              className="h-6 px-2 text-xs"
              onClick={() => {
                if (selectedFromToken) {
                  setFromAmount(formatUnits(selectedFromToken.balance, selectedFromToken.decimals));
                }
              }}
              disabled={!selectedFromToken}
            >
              MAX
            </Button>
          </div>
          <div className="flex gap-2">
            <Input
              type="number"
              placeholder="0.0"
              value={fromAmount}
              onChange={(e) => setFromAmount(e.target.value)}
              className="text-2xl h-16"
            />
            <div className="relative min-w-[160px] space-y-1" ref={fromDropdownRef}>
              <Button
                variant="secondary"
                className="w-full h-16 justify-between"
                onClick={() => setIsFromDropdownOpen(!isFromDropdownOpen)}
              >
                {selectedFromToken ? (
                  <span className="font-medium">{selectedFromToken.symbol}</span>
                ) : (
                  t('swap.selectToken')
                )}
                <ChevronDown className="h-4 w-4 ml-2" />
              </Button>
              <div className="text-xs text-muted-foreground text-right">
                {t('swap.balance')}: {selectedFromToken ? formatUnits(selectedFromToken.balance, selectedFromToken.decimals) : '0.00'}
              </div>
              {isFromDropdownOpen && (
                <div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
                  {tokenDetails && tokenDetails.length > 0 ? (
                    tokenDetails.map((token) => (
                      <button
                        key={token.address}
                        className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
                        onClick={() => {
                          setSelectedFromToken(token);
                          setIsFromDropdownOpen(false);
                        }}
                      >
                        <span className="font-medium">{token.symbol}</span>
                      </button>
                    ))
                  ) : (
                    <div className="px-4 py-3 text-sm text-muted-foreground">
                      {loading ? 'Loading tokens...' : 'No tokens available'}
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>

        {/* Switch Button */}
        <div className="flex justify-center">
          <Button
            variant="ghost"
            size="icon"
            onClick={switchTokens}
            className="rounded-full"
          >
            <ArrowDownUp className="h-4 w-4" />
          </Button>
        </div>

        {/* To Token */}
        <div className="space-y-2">
          <div className="text-sm">
            <label className="text-muted-foreground">{t('swap.youReceive')}</label>
          </div>
          <div className="flex gap-2">
            <Input
              type="number"
              placeholder="0.0"
              value={toAmount}
              onChange={(e) => setToAmount(e.target.value)}
              className="text-2xl h-16"
              disabled={!selectedFromToken}
            />
            <div className="relative min-w-[160px] space-y-1" ref={toDropdownRef}>
              <Button
                variant="secondary"
                className="w-full h-16 justify-between"
                onClick={() => setIsToDropdownOpen(!isToDropdownOpen)}
                disabled={!selectedFromToken}
              >
                {selectedToToken ? (
                  <span className="font-medium">{selectedToToken.symbol}</span>
                ) : (
                  t('swap.selectToken')
                )}
                <ChevronDown className="h-4 w-4 ml-2" />
              </Button>
              <div className="text-xs text-muted-foreground text-right">
                {t('swap.balance')}: {selectedToToken ? formatUnits(selectedToToken.balance, selectedToToken.decimals) : '0.00'}
              </div>
              {isToDropdownOpen && (
                <div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
                  {availableTokens && availableTokens.length > 0 && tokenDetails ? (
                    // Filter tokenDetails to only show tokens in availableTokens
                    tokenDetails
                      .filter((token) =>
                        availableTokens.some((availToken) =>
                          availToken.address.toLowerCase() === token.address.toLowerCase()
                        )
                      )
                      .map((token) => (
                        <button
                          key={token.address}
                          className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
                          onClick={() => {
                            setSelectedToToken(token);
                            setIsToDropdownOpen(false);
                          }}
                        >
                          <span className="font-medium">{token.symbol}</span>
                        </button>
                      ))
                  ) : selectedFromToken ? (
                    <div className="px-4 py-3 text-sm text-muted-foreground">
                      {loading ? 'Loading available tokens...' : poolsError || 'No tokens available for swap'}
                    </div>
                  ) : (
                    <div className="px-4 py-3 text-sm text-muted-foreground">
                      Select a token in "You Pay" first
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>

        {/* Error message for unsupported tokens */}
        {poolsError && selectedFromToken && (
          <div className="px-4 py-3 bg-destructive/10 border border-destructive/20 rounded-lg">
            <p className="text-sm text-destructive">{poolsError}</p>
          </div>
        )}

        {/* Error message for insufficient balance */}
        {hasInsufficientBalance && (
          <div className="px-4 py-3 bg-destructive/10 border border-destructive/20 rounded-lg">
            <p className="text-sm text-destructive">Insufficient balance</p>
          </div>
        )}

        {/* Error message for slippage exceeding 5% */}
        {slippageExceedsLimit && (
          <div className="px-4 py-3 bg-destructive/10 border border-destructive/20 rounded-lg">
            <p className="text-sm text-destructive font-medium">⚠️ Slippage Exceeds 5%</p>
            <p className="text-xs text-destructive/80 mt-1">
              The estimated slippage for this swap is {Math.abs(swapAmounts![0].calculatedSlippage!).toFixed(2)}%.
              We cannot process this swap as you may lose too much money due to the high slippage.
            </p>
          </div>
        )}

        {/* High slippage warning - show if calculated slippage exceeds max slippage but is under 5% */}
        {!slippageExceedsLimit && swapAmounts && swapAmounts.length > 0 && swapAmounts[0].calculatedSlippage !== undefined && (
          Math.abs(swapAmounts[0].calculatedSlippage) > currentSlippage
        ) && (
          <div className="px-4 py-3 bg-yellow-500/10 border border-yellow-500/20 rounded-lg">
            <p className="text-sm text-yellow-600 dark:text-yellow-500 font-medium">⚠️ High Slippage Warning</p>
            <p className="text-xs text-yellow-600/80 dark:text-yellow-500/80 mt-1">
              The estimated slippage for this swap is {Math.abs(swapAmounts[0].calculatedSlippage).toFixed(2)}%. You may lose money due to low liquidity in this pool.
            </p>
          </div>
        )}

        {/* Gas Estimate, Slippage, and Fees */}
        {isConnected && fromAmount && toAmount && (
          <div className="px-4 py-2 bg-muted/30 rounded-lg space-y-2">
            <div className="flex justify-between text-sm">
              <span className="text-muted-foreground">Estimated Gas Cost:</span>
              <span className="font-medium">
                {isEstimatingGas ? 'Calculating...' : gasEstimate ? (gasEstimate.estimatedCostUsd.startsWith('<') ? gasEstimate.estimatedCostUsd : `$${gasEstimate.estimatedCostUsd}`) : '-'}
              </span>
            </div>
            <div className="flex justify-between text-sm">
              <span className="text-muted-foreground">Max Slippage:</span>
              <span className="font-medium">{maxSlippage}%</span>
            </div>
            {swapAmounts && swapAmounts.length > 0 && selectedFromToken && fromAmount && (
              <>
                <div className="flex justify-between text-sm">
                  <span className="text-muted-foreground">Total Amount In:</span>
                  <span className="font-medium">
                    {formatUnits(swapAmounts[0].amountIn, selectedFromToken.decimals)} {selectedFromToken.symbol}
                  </span>
                </div>
                <div className="flex justify-between text-sm">
                  <span className="text-muted-foreground">Fee:</span>
                  <span className="font-medium">
                    {formatUnits(swapAmounts[0].fee, selectedFromToken.decimals)} {selectedFromToken.symbol}
                    {' '}
                    ({((Number(swapAmounts[0].fee) / Number(swapAmounts[0].amountIn)) * 100).toFixed(2)}%)
                  </span>
                </div>
              </>
            )}
          </div>
        )}

        {/* Review Button */}
        <Button
          className="w-full h-14 text-lg"
          onClick={() => setIsReviewModalOpen(true)}
          disabled={!isConnected || !fromAmount || !toAmount || !!poolsError || hasInsufficientBalance || slippageExceedsLimit}
        >
          {!isConnected
            ? t('swap.connectWalletToSwap')
            : hasInsufficientBalance
            ? 'Insufficient Balance'
            : slippageExceedsLimit
            ? 'Slippage Too High'
            : 'Review'}
        </Button>
      </CardContent>

      {/* Settings Modal */}
      {isSettingsOpen && (
        <>
          <div
            className="fixed inset-0 z-50 bg-black/80 animate-in fade-in-0"
            onClick={() => setIsSettingsOpen(false)}
          />
          <div className="fixed left-[50%] top-[50%] z-50 w-full max-w-sm translate-x-[-50%] translate-y-[-50%] animate-in fade-in-0 zoom-in-95">
            <div className="bg-background border rounded-lg shadow-lg p-6">
              <div className="flex justify-between items-center mb-4">
                <h2 className="text-lg font-semibold">Settings</h2>
                <button
                  onClick={() => setIsSettingsOpen(false)}
                  className="rounded-sm opacity-70 hover:opacity-100 transition-opacity"
                >
                  <ChevronDown className="h-4 w-4" />
                </button>
              </div>

              <div className="space-y-4">
                <div>
                  <label className="text-sm font-medium block mb-2">
                    Max Slippage
                  </label>
                  <div className="relative">
                    <Input
                      type="number"
                      value={maxSlippage}
                      onChange={(e) => setMaxSlippage(e.target.value)}
                      className="pr-8"
                      step="0.1"
                      min="0"
                      max="100"
                    />
                    <span className="absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground">
                      %
                    </span>
                  </div>
                  <p className="text-xs text-muted-foreground mt-2">
                    Your transaction will revert if the price changes unfavorably by more than this percentage.
                  </p>
                </div>
              </div>
            </div>
          </div>
        </>
      )}

      {/* Review Modal */}
      <SwapReviewModal
        open={isReviewModalOpen}
        onOpenChange={setIsReviewModalOpen}
        fromToken={selectedFromToken}
        toToken={selectedToToken}
        fromAmount={fromAmount}
        toAmount={toAmount}
        slippage={currentSlippage}
        gasEstimate={gasEstimate}
        fee={swapAmounts && swapAmounts.length > 0 ? swapAmounts[0].fee : null}
        onConfirm={async () => {
          await handleSwap();
          setIsReviewModalOpen(false);
        }}
        isSwapping={isSwapping}
      />

      {/* Transaction Modal Overlay */}
      {transactionStatus !== 'idle' && (
        <div className="absolute inset-0 bg-background/80 backdrop-blur-sm flex items-center justify-center z-50 rounded-lg">
          <div className="bg-card border rounded-lg p-8 max-w-sm w-full mx-4 shadow-lg">
            {transactionStatus === 'pending' && (
              <div className="flex flex-col items-center space-y-4">
                <Loader2 className="h-16 w-16 animate-spin text-primary" />
                <h3 className="text-xl font-semibold text-center">Approving Swap</h3>
                <p className="text-sm text-muted-foreground text-center">
                  Swapping {fromAmount} {selectedFromToken?.symbol} → {toAmount} {selectedToToken?.symbol}
                </p>
                <p className="text-xs text-muted-foreground text-center">
                  Please confirm the transactions in your wallet
                </p>
              </div>
            )}

            {transactionStatus === 'success' && (
              <div className="flex flex-col items-center space-y-4">
                <CheckCircle className="h-16 w-16 text-green-500" />
                <h3 className="text-xl font-semibold text-center">Swap Confirmed!</h3>

                {/* Display actual amounts or estimates */}
                <div className="w-full space-y-3">
                  {actualSwapAmounts && selectedFromToken && selectedToToken ? (
                    // Show actual amounts from transaction
                    <>
                      <div className="flex justify-between text-sm">
                        <span className="text-muted-foreground">Swapped:</span>
                        <span className="font-medium">{formatUnits(actualSwapAmounts.amountIn, selectedFromToken.decimals)} {selectedFromToken.symbol}</span>
                      </div>
                      <div className="flex justify-between text-sm">
                        <span className="text-muted-foreground">Received:</span>
                        <span className="font-medium">{formatUnits(actualSwapAmounts.amountOut, selectedToToken.decimals)} {selectedToToken.symbol}</span>
                      </div>
                      <div className="flex justify-between text-sm">
                        <span className="text-muted-foreground">Fee:</span>
                        <span className="font-medium">{formatUnits(actualSwapAmounts.lpFee + actualSwapAmounts.protocolFee, selectedFromToken.decimals)} {selectedFromToken.symbol}</span>
                      </div>
                    </>
                  ) : (
                    // Fallback to estimates
                    <>
                      <p className="text-sm text-muted-foreground text-center">
                        Successfully swapped {fromAmount} {selectedFromToken?.symbol} to {toAmount} {selectedToToken?.symbol}
                        <br />
                        <span className="text-xs italic opacity-70">
                          *Disclaimer: This is an estimate from the protocol. The actual amounts might be slightly different due to slippage.
                        </span>
                      </p>
                    </>
                  )}
                </div>

                <Button
                  onClick={handleCloseModal}
                  className="w-full mt-4"
                >
                  Close
                </Button>
              </div>
            )}

            {transactionStatus === 'error' && (
              <div className="flex flex-col items-center space-y-4">
                <XCircle className="h-16 w-16 text-destructive" />
                <h3 className="text-xl font-semibold text-center">Swap Failed</h3>
                <p className="text-sm text-muted-foreground text-center break-words">
                  {transactionError || 'Transaction failed'}
                </p>
                <Button
                  onClick={handleCloseModal}
                  variant="outline"
                  className="w-full mt-4"
                >
                  Close
                </Button>
              </div>
            )}
          </div>
        </div>
      )}
    </Card>
  );
}
