"use client";

import {
  Children,
  isValidElement,
  type ReactNode,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";

import { GoArrowDown } from "react-icons/go";
import { useI18n } from "@/translations/provider";
import { useQuestionProgress } from "./question-progress-tracker";

const WHEEL_GESTURE_IDLE_MS = 320;
const TOUCH_MIN_DISTANCE = 8;
const AUTO_FOCUS_SELECTOR = [
  "textarea:not([disabled])",
  'input[type="text"]:not([disabled])',
  'input[type="number"]:not([disabled])',
].join(", ");

type QuestionSnapListProps = {
  children: ReactNode;
  className?: string;
  footer?: ReactNode;
  firstQuestionHint?: ReactNode;
  onQuestionExit?: (currentIndex: number, nextIndex: number) => void;
  onQuestionTransition?: (currentIndex: number, nextIndex: number) => void;
};

export function QuestionSnapList({
  children,
  className,
  footer,
  firstQuestionHint,
  onQuestionExit,
  onQuestionTransition,
}: QuestionSnapListProps) {
  const { dictionary: t } = useI18n();
  const { isCompleted } = useQuestionProgress();
  const questions = Children.toArray(children);
  const wheelLockedRef = useRef(false);
  const wheelUnlockTimeoutRef = useRef<number | null>(null);
  const touchStartYRef = useRef<number | null>(null);
  const questionRefs = useRef<Array<HTMLDivElement | null>>([]);
  const previousActiveIndexRef = useRef<number | null>(null);
  const [activeIndex, setActiveIndex] = useState(0);

  // Track whether section was already completed on mount
  const wasCompletedOnMountRef = useRef<boolean | null>(null);
  const [justCompleted, setJustCompleted] = useState(false);

  useEffect(() => {
    if (wasCompletedOnMountRef.current === null) {
      // First time: capture the initial state
      wasCompletedOnMountRef.current = isCompleted;
      return;
    }
    // Only show button if it was NOT completed on mount and now becomes completed
    if (!wasCompletedOnMountRef.current && isCompleted) {
      setJustCompleted(true);
    }
  }, [isCompleted]);

  const stepQuestion = useCallback(
    (direction: 1 | -1) => {
      const nextIndex = Math.max(
        0,
        Math.min(questions.length - 1, activeIndex + direction),
      );

      if (nextIndex === activeIndex) {
        return;
      }

      onQuestionExit?.(activeIndex, nextIndex);

      onQuestionTransition?.(activeIndex, nextIndex);

      setActiveIndex(nextIndex);
    },
    [activeIndex, onQuestionExit, onQuestionTransition, questions.length],
  );

  const scheduleWheelUnlock = useCallback(() => {
    if (wheelUnlockTimeoutRef.current !== null) {
      window.clearTimeout(wheelUnlockTimeoutRef.current);
    }

    wheelUnlockTimeoutRef.current = window.setTimeout(() => {
      wheelLockedRef.current = false;
      wheelUnlockTimeoutRef.current = null;
    }, WHEEL_GESTURE_IDLE_MS);
  }, []);

  const hasInitializedActiveIndexRef = useRef(false);

  useEffect(() => {
    if (hasInitializedActiveIndexRef.current || questions.length === 0) {
      return;
    }

    const timerId = window.setTimeout(() => {
      if (hasInitializedActiveIndexRef.current) {
        return;
      }

      for (let index = 0; index < questions.length; index += 1) {
        const questionElement = questionRefs.current[index];

        if (!questionElement) {
          continue;
        }

        const isDisabled =
          questionElement.getAttribute("data-question-disabled") === "true" ||
          questionElement.querySelector("[data-question-disabled='true']") !== null;

        if (isDisabled) {
          continue;
        }

        const explicitAnsweredState =
          questionElement.getAttribute("data-question-answered") ??
          questionElement
            .querySelector("[data-question-answered]")
            ?.getAttribute("data-question-answered");

        const isAnswered =
          explicitAnsweredState === "true" ||
          (explicitAnsweredState !== "false" &&
            Array.from(
              questionElement.querySelectorAll<
                HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
              >("input, select, textarea"),
            ).some((input) => {
              if (input instanceof HTMLInputElement) {
                if (input.type === "checkbox" || input.type === "radio") {
                  return input.checked;
                }
                if (input.type === "file") {
                  return input.files !== null && input.files.length > 0;
                }
              }
              return input.value.trim().length > 0;
            }));

        if (!isAnswered) {
          hasInitializedActiveIndexRef.current = true;
          setActiveIndex(index);
          return;
        }
      }

      hasInitializedActiveIndexRef.current = true;
    }, 50);

    return () => {
      window.clearTimeout(timerId);
    };
  }, [questions.length]);

  useEffect(() => {
    const previousActiveIndex = previousActiveIndexRef.current;

    onQuestionTransition?.(previousActiveIndex ?? activeIndex, activeIndex);
    previousActiveIndexRef.current = activeIndex;
  }, [activeIndex, onQuestionTransition]);

  useEffect(() => {
    const activeQuestion = questionRefs.current[activeIndex];

    if (!activeQuestion) {
      return;
    }

    const focusFrame = window.requestAnimationFrame(() => {
      if (document.querySelector('[role="dialog"]')) {
        return;
      }

      const firstFocusableInput = activeQuestion.querySelector<
        HTMLInputElement | HTMLTextAreaElement
      >(AUTO_FOCUS_SELECTOR);

      if (!firstFocusableInput) {
        return;
      }

      const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
        navigator.userAgent
      );

      firstFocusableInput.focus({ preventScroll: !isMobile });

      if (isMobile) {
        setTimeout(() => {
          firstFocusableInput.scrollIntoView({
            behavior: "smooth",
            block: "center",
          });
        }, 150);
      }

      const valueLength = firstFocusableInput.value.length;

      if (
        valueLength > 0 &&
        typeof firstFocusableInput.setSelectionRange === "function"
      ) {
        firstFocusableInput.setSelectionRange(valueLength, valueLength);
      }
    });

    return () => {
      window.cancelAnimationFrame(focusFrame);
    };
  }, [activeIndex]);

  useEffect(() => {
    return () => {
      if (wheelUnlockTimeoutRef.current !== null) {
        window.clearTimeout(wheelUnlockTimeoutRef.current);
      }
    };
  }, []);

  const handleWheel = useCallback(
    (event: React.WheelEvent<HTMLElement>) => {
      if (document.body.classList.contains("dropdown-open")) {
        return;
      }

      const delta = event.deltaY || event.deltaX;

      if (delta === 0 || questions.length < 2) {
        return;
      }

      event.preventDefault();

      if (!wheelLockedRef.current) {
        wheelLockedRef.current = true;
        stepQuestion(delta > 0 ? 1 : -1);
      }

      scheduleWheelUnlock();
    },
    [questions.length, scheduleWheelUnlock, stepQuestion],
  );

  const handleTouchStart = useCallback(
    (event: React.TouchEvent<HTMLElement>) => {
      if (document.body.classList.contains("dropdown-open")) {
        return;
      }
      touchStartYRef.current = event.touches[0]?.clientY ?? null;
    },
    [],
  );

  const handleTouchEnd = useCallback(
    (event: React.TouchEvent<HTMLElement>) => {
      if (document.body.classList.contains("dropdown-open")) {
        return;
      }

      const startY = touchStartYRef.current;
      const endY = event.changedTouches[0]?.clientY;

      touchStartYRef.current = null;

      if (startY === null || endY === undefined || questions.length < 2) {
        return;
      }

      const distance = startY - endY;

      if (Math.abs(distance) < TOUCH_MIN_DISTANCE) {
        return;
      }

      stepQuestion(distance > 0 ? 1 : -1);
    },
    [questions.length, stepQuestion],
  );

  const handleTouchMove = useCallback(
    (event: React.TouchEvent<HTMLElement>) => {
      if (document.body.classList.contains("dropdown-open")) {
        return;
      }
      event.preventDefault();
    },
    [],
  );

  if (questions.length === 0) {
    return null;
  }

  return (
    <section
      aria-label="Questions"
      className={[
        "relative touch-none overflow-hidden focus-visible:outline-none",
        "flex-1 min-h-0 pt-4 pb-4",
        className,
      ]
        .filter(Boolean)
        .join(" ")}
      onTouchEnd={handleTouchEnd}
      onTouchMove={handleTouchMove}
      onTouchStart={handleTouchStart}
      onWheel={handleWheel}
    >
      {questions.map((question, index) => {
        const offset = index - activeIndex;
        const isActive = offset === 0;
        const isPrev = offset === -1;
        const isNext = offset === 1;
        const questionKey =
          isValidElement(question) && question.key !== null
            ? question.key
            : String(question);

        let containerStyles = "";
        let wrapperStyles = "w-full";

        if (isActive) {
          containerStyles = "top-[35%] left-0 -translate-y-1/2 z-10 opacity-100 scale-100 pointer-events-auto";
        } else if (isPrev) {
          containerStyles = "top-4 left-0 z-0 opacity-0 pointer-events-none scale-[0.98]";
          wrapperStyles = "w-full max-h-[110px] overflow-hidden pointer-events-none";
        } else if (isNext) {
          containerStyles = "bottom-4 left-0 z-0 opacity-0 pointer-events-none scale-[0.98]";
          wrapperStyles = "w-full max-h-[110px] overflow-hidden pointer-events-none";
        } else {
          containerStyles = "top-1/2 left-0 -translate-y-1/2 z-0 opacity-0 pointer-events-none scale-[0.95]";
          wrapperStyles = "w-full max-h-[110px] overflow-hidden pointer-events-none";
        }

        return (
          <div
            key={questionKey}
            ref={(element) => {
              questionRefs.current[index] = element;
            }}
            aria-current={isActive ? "step" : undefined}
            aria-hidden={isActive ? undefined : true}
            inert={isActive ? undefined : true}
            className={[
              "absolute flex w-full flex-col justify-center transition-all duration-300 ease-out px-[17px]",
              containerStyles,
            ].join(" ")}
          >
            <div className={wrapperStyles}>
              {question}
            </div>
          </div>
        );
      })}
      {footer && activeIndex === questions.length - 1 ? (
        <div className="pointer-events-none fixed bottom-0 left-1/2 z-20 w-full sm:max-w-[375px] -translate-x-1/2 bg-[#F5F5F5]">
          <div
            style={{ paddingBottom: "calc(24px + var(--safe-bottom))" }}
            className="pointer-events-auto px-[17px] pt-3"
          >
            {footer}
          </div>
        </div>
      ) : null}
      {firstQuestionHint ? (
        <div
          aria-hidden="true"
          className={[
            "pointer-events-none absolute bottom-6 left-1/2 -translate-x-1/2",
            "transition-opacity duration-500  motion-safe:animate-bounce",
            activeIndex === 0 ? "opacity-100" : "opacity-0",
          ].join(" ")}
        >
          {firstQuestionHint}
        </div>
      ) : null}
      {justCompleted && activeIndex < questions.length - 1 ? (
        <button
          type="button"
          onClick={() => {
            onQuestionExit?.(activeIndex, questions.length - 1);
            onQuestionTransition?.(activeIndex, questions.length - 1);
            setActiveIndex(questions.length - 1);
          }}
          className="fixed right-[max(16px,calc(50%-170px))] bottom-6 z-30 inline-flex items-center gap-1.5 rounded-full bg-[#1B1B1B]/90 px-3.5 py-2 text-xs font-semibold text-white shadow-[0_8px_20px_rgba(0,0,0,0.22)] backdrop-blur-md transition-all duration-300 hover:bg-[#1B1B1B] active:scale-95 cursor-pointer animate-in fade-in slide-in-from-right-4"
        >
          <GoArrowDown className="size-3.5 motion-safe:animate-bounce" />
          <span>{t.questions?.moveToEnd ?? "Move to the End"}</span>
        </button>
      ) : null}
    </section>
  );
}

export default QuestionSnapList;
