import { BuyIcon } from "@src/assets";
import { Skeleton, TokenLogo } from "@src/components";
import { useSwapContext } from "@src/contexts";
import { RoutePath } from "@src/interfaces";
import { TokenWithChain } from "@src/models";
import { useNavigate } from "react-router-dom";
import { useEffect, useMemo, useRef, useState } from "react";
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
import { abbreviateNumber } from "@src/utils";
import { usePnL } from "../hooks/usePnL";

interface Props {
  token: TokenWithChain;
  previousAmount?: string;
  previousValue?: string;
  currentAmount: string;
  currentValue: string;
}

export const YourTokenItem = ({
  token,
  previousAmount,
  previousValue,
  currentAmount,
  currentValue,
}: Props) => {
  const {
    supportedChainsMap,
    setToken,
    setChain,
    isFetchingBalances,
    isMultichain,
  } = useSwapContext();
  const navigate = useNavigate();
  const pnlData = usePnL();
  const parsedCurrentValue = parseFloat(currentValue);
  const parsedCurrentAmount = parseFloat(currentAmount);
  const parsedPrevValue = parseFloat(previousValue || "0");
  const parsedPrevAmount = parseFloat(previousAmount || "0");

  const shouldAnimate =
    previousValue !== undefined && parsedCurrentValue > parsedPrevValue;

  const value = useMotionValue(
    shouldAnimate ? parsedPrevValue : parsedCurrentValue,
  );
  const amount = useMotionValue(
    shouldAnimate ? parsedPrevAmount : parsedCurrentAmount,
  );

  const animatedValue = useSpring(value, { stiffness: 90, damping: 20 });
  const animatedAmount = useSpring(amount, { stiffness: 90, damping: 20 });

  const formattedValue = useTransform(
    animatedValue,
    (v) => `$${abbreviateNumber(v, 2)}`,
  );
  const formattedAmount = useTransform(animatedAmount, (v) =>
    abbreviateNumber(v),
  );

  const prevValueRef = useRef(parsedPrevValue);
  const prevAmountRef = useRef(parsedPrevAmount);

  const [isAnimating, setIsAnimating] = useState(false);

  useEffect(() => {
    if (previousValue && parsedCurrentValue > prevValueRef.current) {
      setIsAnimating(true);
      value.set(prevValueRef.current);
      amount.set(prevAmountRef.current);

      requestAnimationFrame(() => {
        value.set(parsedCurrentValue);
        amount.set(parsedCurrentAmount);
      });

      const unsubscribe = animatedValue.on("change", (v) => {
        if (Math.abs(v - parsedCurrentValue) < 0.01) {
          setIsAnimating(false);
          unsubscribe();
        }
      });
    } else {
      value.set(parsedCurrentValue);
      amount.set(parsedCurrentAmount);
    }

    prevValueRef.current = parsedCurrentValue;
    prevAmountRef.current = parsedCurrentAmount;
  }, [
    previousValue,
    parsedCurrentValue,
    parsedCurrentAmount,
    value,
    amount,
    animatedValue,
  ]);

  const renderPnL = (percentageChange: number) => {
    const isPositive = percentageChange >= 0;
    return (
      <span
        className={`text-xs leading-3 font-bold ${
          isPositive ? "text-success_color" : "text-error_color"
        }`}
      >
        {`${isPositive ? "+" : "-"} ${Math.abs(percentageChange).toFixed(2)}%`}
      </span>
    );
  };

  const tokenAllTimePnLPercentage = useMemo(() => {
    return pnlData?.tokenPnLs.find(
      (e) => e.tokenAddress === token.address && e.chainId === token.chainId,
    )?.allTimePnLPercent;
  }, [pnlData, token]);

  return (
    <motion.div
      className={`py-2 px-4 flex justify-between gap-2 items-center rounded-xl`}
      animate={{
        backgroundColor: isAnimating
          ? "var(--swapper-primary-color)"
          : "rgba(0,0,0,0)",
        color: isAnimating
          ? "var(--swapper-bg-color)"
          : "var(--swapper-bg-color)",
      }}
    >
      <div className="flex gap-3 items-center">
        <TokenLogo
          token={token}
          tokenLogoClassName="w-8 min-w-8 h-8"
          unknownTokenLogoClassName="w-8 min-w-8 h-8 text-md"
          withChain={isMultichain}
          chain={supportedChainsMap[token.chainId]}
        />
        <div
          className={`text-xl font-medium ${
            isAnimating ? "text-white" : "text-text_primary"
          }`}
        >
          {token.symbol}
        </div>
      </div>
      <div className="flex gap-3 items-center">
        <div className="flex flex-col gap-1 items-end">
          {currentValue && (
            <motion.div
              className={`flex gap-1 text-xs font-bold leading-3`}
              animate={{
                color: isAnimating ? "#4ade80" : "var(--swapper-text-color)",
              }}
              transition={{ duration: 0.3 }}
            >
              {tokenAllTimePnLPercentage !== undefined && (
                <motion.span>
                  {renderPnL(tokenAllTimePnLPercentage)}
                </motion.span>
              )}
              <motion.span>{formattedValue}</motion.span>
            </motion.div>
          )}

          {isFetchingBalances ? (
            <Skeleton className="w-8 h-3" />
          ) : (
            <motion.div
              className={`text-xs text-opacity-60 leading-3`}
              animate={{
                color: isAnimating ? "#4ade80" : "var(--swapper-text-color)",
              }}
              transition={{ duration: 0.3 }}
            >
              {formattedAmount}
            </motion.div>
          )}
        </div>
        <div
          className="hover:cursor-pointer"
          onClick={() => {
            setToken(token);
            setChain(supportedChainsMap[token.chainId]);
            navigate(RoutePath.Buy);
          }}
        >
          <BuyIcon
            className={`w-6 h-6 ${
              isAnimating ? "!fill-white" : "!fill-theme_color"
            }`}
          />
        </div>
      </div>
    </motion.div>
  );
};
