"use client";
import useHaptic from "@/lib/hooks/useHaptics";
import { cn } from "@/lib/utils";
import { useResizeObserver } from "@mantine/hooks";
import {
  motion,
  useMotionValue,
  animate,
  useTransform,
  MotionConfig,
  AnimatePresence,
  useMotionValueEvent,
  useSpring,
  Transition,
  ValueAnimationTransition,
  SpringOptions,
} from "framer-motion";
import React, {
  PropsWithChildren,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";

interface SlideToConfirmProps extends PropsWithChildren {
  onSlideComplete?: () => void;
  onLongPress?: () => void;
  holdTreshold?: number;
}
export function SlideToConfirm(props: SlideToConfirmProps) {
  const { onSlideComplete, onLongPress, holdTreshold = 500 } = props;

  const { triggerHapticFeedback, isHapticSupported } = useHaptic();

  const [isSlideComplete, setIsSlideComplete] = useState(false);
  const [isLongPressed, setIsLongPressed] = useState(false);

  const clientX = useMotionValue(0);

  const thumbWrapperWidth = useMotionValue(0);
  const thumbX = useMotionValue(0);

  const [refThumbWrapper, thumbWrapperRect] = useResizeObserver();
  const [refThumb, thumbRect] = useResizeObserver();
  const [refTrack, trackRect] = useResizeObserver();

  const [isDragging, setIsDragging] = useState(false);

  const startRef = useRef({ x: 0, width: thumbWrapperRect.height });
  const [thumbXMax, setThumbXMax] = useState(0);

  const longPressTimerRef = useRef<NodeJS.Timeout | null>(null);
  const longPressThreshold = holdTreshold;

  const transition: Transition = !isSlideComplete
    ? {
        type: "spring",
        stiffness: 100,
        damping: 7,
        mass: 0.2,
      }
    : {
        type: "tween",
        duration: 0.27,
        ease: "easeOut",
      };

  const valueTransition: ValueAnimationTransition = { ...transition };

  useEffect(() => {
    setThumbXMax(
      trackRect.width - thumbRect.width - refThumb.current?.offsetLeft * 2,
    );
    startRef.current.width = thumbWrapperRect.height;
  }, [trackRect, thumbRect, refThumb, thumbWrapperRect.height]);

  const handleConfetti = useCallback(async () => {
    const { clientWidth, clientHeight } = document.documentElement;
    const boundingBox = refThumb.current?.getBoundingClientRect?.();

    const targetY = boundingBox?.y ?? 0;
    const targetX = boundingBox?.x ?? 0;
    const targetWidth = boundingBox?.width ?? 0;

    const targetCenterX = targetX + targetWidth / 2;

    function randomInRange(min: number, max: number) {
      return Math.random() * (max - min) + min;
    }

    const confetti = (await import("canvas-confetti")).default;

    confetti({
      angle: randomInRange(120, 120),
      spread: randomInRange(50, 70),
      particleCount: randomInRange(50, 100),
      zIndex: 999,
      ticks: 60,
      origin: {
        // y: targetY / clientHeight,
        x: targetCenterX / clientWidth,
      },
    });
  }, [refThumb]);

  const startLongPressTimer = useCallback(() => {
    if (longPressTimerRef.current) clearTimeout(longPressTimerRef.current);
    longPressTimerRef.current = setTimeout(() => {
      setIsLongPressed(true);
      onLongPress?.();
      triggerHapticFeedback(200);
      handleConfetti();
    }, longPressThreshold);
  }, [longPressThreshold, onLongPress, triggerHapticFeedback, handleConfetti]);

  const clearLongPressTimer = useCallback(() => {
    if (longPressTimerRef.current) {
      setIsLongPressed(false);
      clearTimeout(longPressTimerRef.current);
      longPressTimerRef.current = null;
    }
  }, []);

  const checkSlideComplete = useCallback(() => {
    return thumbX.get() >= thumbXMax;
  }, [thumbX, thumbXMax]);

  const OnSlideComplete = () => {
    if (checkSlideComplete()) {
      setIsSlideComplete(true);
      if (!isSlideComplete) {
        onSlideComplete?.();
        triggerHapticFeedback(100);
        startLongPressTimer();
      }
    } else {
      setIsSlideComplete(false);
      clearLongPressTimer();
    }
  };

  useMotionValueEvent(clientX, "change", (latest: number) => {
    const dx =
      latest -
      startRef.current.x -
      trackRect.left +
      refThumb.current.offsetLeft * 2;
    let newWidth = Math.max(
      startRef.current.width,
      startRef.current.width + dx,
    );
    // newWidth = clamp(startRef.current.width, trackRect.width, newWidth);
    thumbWrapperWidth.jump(newWidth);

    let newX = latest - startRef.current.x - trackRect.left + thumbRect.left;
    // newX = clamp(0, thumbXMax, newX);
    thumbX.jump(newX);
  });

  const thumbXClamped = useTransform(thumbX, [0, thumbXMax], [0, thumbXMax]);
  const thumbXSpring = useSpring(thumbXClamped, {
    ...transition,
  } as SpringOptions);

  const thumbWrapperWidthClamped = useTransform(
    thumbWrapperWidth,
    [startRef.current.width, trackRect.width],
    [startRef.current.width, trackRect.width],
  );
  const thumbWrapperWidthSpring = useSpring(thumbWrapperWidthClamped, {
    ...transition,
  } as SpringOptions);

  const handlePointerDown = (event: React.PointerEvent) => {
    startRef.current = {
      x: event.clientX,
      width: thumbWrapperRect.height,
    };
    setIsDragging(true);
  };

  const handlePointerMove = (event: React.PointerEvent) => {
    event.preventDefault();
    if (!isDragging) return;
    (event.target as HTMLDivElement).setPointerCapture(event.pointerId);
    clientX.jump(event.clientX);
    OnSlideComplete();
  };

  const handlePointerUp = () => {
    setIsDragging(false);
    animate(clientX, 0, {
      ...valueTransition,
    });
    clearLongPressTimer();
    setIsSlideComplete(false);
  };

  const [isClient, setIsClient] = useState(false);

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

  const [cannon, setCannon] = useState(false);
  useEffect(() => {
    if (cannon == true) {
      setCannon(false);
    }
  }, [cannon]);

  return (
    <MotionConfig transition={{ ...transition }}>
      <motion.div
        initial={{
          opacity: 0,
          scale: 0.8,
        }}
        animate={{
          opacity: refThumb.current ? 1 : 0,
          scale: 1,
        }}
        ref={refTrack}
        className={cn(
          "max-w-72 overflow-hidden min-w-48 touch-none relative border w-full h-16 bg-neutral-50/10 rounded-3xl border-neutral-50/10 flex justify-between items-center",
        )}
      >
        <AnimatePresence>
          {isSlideComplete && (
            <motion.div
              layout={"size"}
              initial={{
                width: 0,
                borderRadius: "24px",
                originX: 0,
              }}
              animate={{
                originX: 0,
                borderRadius: "24px",
                width: trackRect.width,
              }}
              exit={{
                originX: 0,
                borderRadius: "24px",
                width: 0,
                opacity: 0,
                transition: {
                  width: {
                    duration: 0.27,
                    ease: "easeOut",
                  },
                },
              }}
              transition={{
                width: {
                  duration: holdTreshold / 1000,
                  ease: "easeOut",
                },
              }}
              className="absolute left-0 inset-y-0 blur-md bg-gradient-to-r from-transparent to-emerald-500/50"
            />
          )}
        </AnimatePresence>
        <motion.div
          style={{
            width: refThumb.current
              ? `calc(100% - ${startRef.current.width}px)`
              : "100%",
            x:
              thumbX.get() < thumbXMax / 2
                ? `${startRef.current.width}px`
                : "0",
          }}
          className={cn(
            "flex-1 pointer-events-none absolute duration-300 select-none h-full flex justify-center items-center",
          )}
        >
          <div>
            <AnimatePresence mode="wait">
              {isLongPressed ? (
                <motion.div
                  key="release"
                  initial={{
                    opacity: 0,
                    y: 20,
                  }}
                  animate={{
                    opacity: 1,
                    y: 0,
                    transition: {
                      duration: 0.1,
                    },
                  }}
                  exit={{
                    opacity: 0,
                    y: -20,
                    transition: {
                      duration: 0.1,
                    },
                  }}
                  className="text-white w-full text-nowrap font-medium select-none"
                >
                  Release
                </motion.div>
              ) : (
                <motion.div
                  key="slide"
                  initial={{
                    opacity: 0,
                    y: 20,
                  }}
                  animate={{
                    opacity: 1,
                    y: 0,
                    transition: {
                      duration: 0.1,
                    },
                  }}
                  exit={{
                    opacity: 0,
                    y: -20,
                    transition: {
                      duration: 0.1,
                    },
                  }}
                  className="text-white w-full text-nowrap font-medium select-none"
                >
                  Slide & Hold
                </motion.div>
              )}
            </AnimatePresence>
          </div>
        </motion.div>
        <motion.div
          ref={refThumbWrapper}
          onPointerDown={handlePointerDown}
          onPointerMove={handlePointerMove}
          onLostPointerCapture={handlePointerUp}
          onPointerCancel={handlePointerUp}
          onPointerUp={handlePointerUp}
          style={{
            width: useTransform(() => thumbWrapperWidthSpring.get()),
          }}
          className={cn(
            "min-w-16 z-10 rounded-[23px] cursor-grab active:cursor-grabbing relative bg-gradient-to-r from-transparent to-neutral-50/20 h-full flex justify-start items-center p-2 aspect-square",
          )}
        >
          <motion.div
            ref={refThumb}
            style={{
              x: useTransform(() => thumbXSpring.get()),
            }}
            className={cn(
              "flex justify-center items-center h-full aspect-square rounded-2xl transition-colors",
              isSlideComplete ? "bg-emerald-500" : "bg-neutral-100",
            )}
          >
            <div className="w-full h-full flex justify-center items-center space-x-0.5">
              <div
                className={cn(
                  "h-4 w-1 animate-[pulse_1.3s_ease_0ms_infinite] delay-0 rounded-2xl border-t-[1px] border-l-[1px] transition-colors",
                  isSlideComplete
                    ? "bg-emerald-200 border-emerald-400/40"
                    : "bg-neutral-400/60 border-neutral-400/40",
                )}
              />
              <div
                className={cn(
                  "h-3 w-1 animate-[pulse_1.3s_ease_250ms_infinite] delay-150 rounded-2xl border-t-[1px] border-l-[1px] transition-colors",
                  isSlideComplete
                    ? "bg-emerald-200 border-emerald-400/40"
                    : "bg-neutral-400/60 border-neutral-400/40",
                )}
              />
              <div
                className={cn(
                  "h-1.5 w-1 animate-[pulse_1.3s_ease_500ms_infinite] delay-300 rounded-2xl border-t-[1px] border-l-[1px] transition-colors",
                  isSlideComplete
                    ? "bg-emerald-200 border-emerald-400/40"
                    : "bg-neutral-400/60 border-neutral-400/40",
                )}
              />
            </div>
          </motion.div>
        </motion.div>
      </motion.div>
      {isClient && (
        <motion.div className="text-xs mt-8 font-medium text-neutral-500">
          Haptics:{" "}
          <motion.span>
            {isHapticSupported ? "Supported" : "Unsupported"}
          </motion.span>
        </motion.div>
      )}
      {/* <motion.div className="text-xs font-medium text-neutral-500">
        isLongPressed: <motion.span>{isLongPressed.toString()}</motion.span>
      </motion.div>
      <motion.div className="text-xs font-medium text-neutral-500">
        isSlideComplete: <motion.span>{isSlideComplete.toString()}</motion.span>
      </motion.div> */}
    </MotionConfig>
  );
}


this is the code I explored and made.
Write a linkedIn Post for exploration - My journey to Conquering a Significant Challenge! Include details about the challenge, how you
faced it, and what you learned from the experience. Wite about the drag and hold to initiate or trigger an event. Slide and hold. Include learnings and challenges mainly with offsets and pointer/touch positions. a short first post on linkedin.