import { useEffect, useMemo, useRef } from "react";
import Lottie, { LottieRefCurrentProps } from "lottie-react";
import animationData from "./starAnimation.json";

const LABEL_HEIGHT = 33;
const GAP_HEIGHT = 16;
const STEP_HEIGHT = LABEL_HEIGHT + GAP_HEIGHT;
const ANIMATION_HEIGHT_OFFSET = 5;
const SCROLL_ANIMATION_TIMEOUT_MS = 2633; // Delay before starting the scroll animation (matches when the chart starts scaling up in the Lottie animation)
const SCROLL_ANIMATION_DURATION_MS = 967; // Duration of the scroll animation (matches the duration of the chart scaling animation: 2633ms → 3333ms)

const getStepForRange = (range: number): number => {
  if (range <= 10) return 1;
  if (range <= 20) return 2;
  if (range <= 50) return 5;
  if (range <= 100) return 10;
  if (range <= 500) return 25;
  if (range <= 1000) return 50;
  return 100;
};

const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);

const smoothScrollTo = (
  container: HTMLElement,
  target: number,
  duration = 600,
) => {
  const start = container.scrollTop;
  const distance = target - start;
  const startTime = performance.now();

  const step = (currentTime: number) => {
    const time = Math.min(1, (currentTime - startTime) / duration);
    const eased = easeOutCubic(time);
    container.scrollTop = start + distance * eased;

    if (time < 1) {
      requestAnimationFrame(step);
    }
  };

  requestAnimationFrame(step);
};

export const TradesPointsAnimation = ({
  points,
  previousPoints,
}: {
  points: number;
  previousPoints: number;
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const lottieRef = useRef<LottieRefCurrentProps | null>(null);

  const { labels, minValue, maxValue } = useMemo(() => {
    const buffer = 10;
    const lineCountBelow = 5;

    const rawMin = Math.min(previousPoints, points) - buffer;
    const rawMax = Math.max(previousPoints, points) + 50;
    const step = getStepForRange(points - previousPoints);

    const tentativeMin = Math.floor(rawMin / step) * step;
    const minValue = Math.max(0, tentativeMin - lineCountBelow * step);
    const maxValue = Math.ceil(rawMax / step) * step;

    const steps: number[] = [];
    for (let i = maxValue; i >= minValue; i -= step) {
      steps.push(i);
    }

    return { labels: steps, minValue, maxValue };
  }, [previousPoints, points]);

  useEffect(() => {
    if (!containerRef.current) return;

    const container = containerRef.current;

    const getOffsetForPoint = (value: number) => {
      const relative = (maxValue - value) / (maxValue - minValue);
      const offset =
        relative * ((labels.length - 1) * STEP_HEIGHT) + LABEL_HEIGHT;
      return offset;
    };

    const scrollToValue = (value: number, animate = false) => {
      const offset = getOffsetForPoint(value) + ANIMATION_HEIGHT_OFFSET;
      const scrollTop = offset - container.clientHeight / 2;

      if (animate) {
        smoothScrollTo(container, scrollTop, SCROLL_ANIMATION_DURATION_MS);
      } else {
        container.scrollTop = scrollTop;
      }
    };

    scrollToValue(previousPoints);

    if (points !== previousPoints) {
      const timeout = setTimeout(() => {
        scrollToValue(points, true);
      }, SCROLL_ANIMATION_TIMEOUT_MS);

      return () => clearTimeout(timeout);
    } else {
      if (lottieRef.current) {
        const duration = lottieRef.current.getDuration(true);
        if (typeof duration === "number") {
          lottieRef.current.goToAndStop(duration, true);
        }
      }
    }
  }, [points, previousPoints, labels, maxValue, minValue]);

  return (
    <>
      <div className="absolute w-full h-full">
        <Lottie
          lottieRef={lottieRef}
          animationData={animationData}
          loop={false}
          autoplay={true}
          className="absolute bottom-0"
        />
      </div>
      <div
        className="relative flex-1 flex flex-col gap-4 px-4 py-0 overflow-hidden"
        ref={containerRef}
      >
        {/* CURRENT VALUE MARK (add bg color for debugging) */}
        <div
          className="absolute left-2 w-3 h-3 rounded-full bg-red-500 !bg-transparent"
          style={{
            top: `${
              ((maxValue - points) / (maxValue - minValue)) *
                ((labels.length - 1) * STEP_HEIGHT) +
              LABEL_HEIGHT
            }px`,
            transform: "translateY(-50%)",
          }}
        />

        {/* PREVIOUS VALUE MARK (add bg color for debugging) */}
        <div
          className="absolute left-2 w-3 h-3 rounded-full bg-gray-400 !bg-transparent"
          style={{
            top: `${
              ((maxValue - previousPoints) / (maxValue - minValue)) *
                ((labels.length - 1) * STEP_HEIGHT) +
              LABEL_HEIGHT
            }px`,
            transform: "translateY(-50%)",
          }}
        />
        {labels.map((val, idx) => (
          <div key={val} className="flex flex-col gap-[16px] items-start">
            <p className="text-xs text-text_primary/60">{val}</p>
            <div
              className="w-full h-px bg-text_primary/10"
              style={{ opacity: idx === labels.length - 1 ? 0 : 1 }}
            />
          </div>
        ))}
      </div>
    </>
  );
};
