import { CheckIcon, XIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import gsap from "gsap";
import {
  ChangeEvent,
  ToggleEvent,
  useEffect,
  useId,
  useLayoutEffect,
  useRef,
} from "react";

type PropsType = {
  withIcon?: boolean;
  background?: "dark" | "light";
  backgroundSize?: "sm" | "default";
  name?: string;
  checked?: boolean;
  dataCy?: string;
  onToggle: (e: ToggleEvent<HTMLInputElement>) => void;
  onChange: (e: ChangeEvent<HTMLInputElement>) => void;
};

export function Switch({
  background,
  withIcon,
  backgroundSize,
  name,
  checked = false,
  dataCy,
  onToggle,
  onChange,
}: PropsType) {
  const id = useId();
  const isSm = backgroundSize === "sm";
  const isDark = background === "dark";

  const TRAVEL = isSm ? 28 : 24;

  const thumbRef = useRef<HTMLDivElement>(null);
  const trackRef = useRef<HTMLDivElement>(null);
  const glowRef = useRef<HTMLDivElement>(null);
  const checkWrapRef = useRef<HTMLSpanElement>(null);
  const xWrapRef = useRef<HTMLSpanElement>(null);
  const initialized = useRef(false);
  const activeTweens = useRef<gsap.core.Tween[]>([]);

  useLayoutEffect(() => {
    if (thumbRef.current) {
      gsap.set(thumbRef.current, { x: checked ? TRAVEL : 0 });
    }
    if (withIcon && checkWrapRef.current && xWrapRef.current) {
      gsap.set(checkWrapRef.current, {
        autoAlpha: checked ? 1 : 0,
        rotateY: 0,
      });
      gsap.set(xWrapRef.current, {
        autoAlpha: checked ? 0 : 1,
        rotateY: 0,
      });
    }
    if (glowRef.current) {
      gsap.set(glowRef.current, { autoAlpha: 0, scale: 0.6 });
    }
    initialized.current = true;
    // run once on mount
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (!initialized.current) return;
    if (!thumbRef.current || !trackRef.current) return;

    // Kill in-flight tweens WITHOUT reverting — new tweens will start
    // from wherever the element currently sits, so toggling mid-animation
    // (and toggling ON→OFF after ON has settled) feels symmetric.
    activeTweens.current.forEach((t) => t.kill());
    activeTweens.current = [];

    const tl = gsap.timeline();

    tl.to(thumbRef.current, {
      scaleY: 0.82,
      scaleX: 1.18,
      duration: 0.12,
      ease: "power2.out",
    })
      .to(
        thumbRef.current,
        {
          x: checked ? TRAVEL : 0,
          duration: 0.4,
          ease: "back.out(2.2)",
        },
        "<",
      )
      .to(
        thumbRef.current,
        {
          scaleY: 1,
          scaleX: 1,
          duration: 0.5,
          ease: "elastic.out(1, 0.45)",
        },
        "-=0.2",
      );
    activeTweens.current.push(tl as unknown as gsap.core.Tween);

    activeTweens.current.push(
      gsap.fromTo(
        trackRef.current,
        { scale: 1 },
        {
          scale: 1.05,
          duration: 0.14,
          ease: "power2.out",
          yoyo: true,
          repeat: 1,
        },
      ),
    );

    if (checked && glowRef.current) {
      activeTweens.current.push(
        gsap.fromTo(
          glowRef.current,
          { autoAlpha: 0.85, scale: 0.5 },
          {
            autoAlpha: 0,
            scale: 1.9,
            duration: 0.7,
            ease: "power2.out",
          },
        ),
      );
    }

    if (withIcon && checkWrapRef.current && xWrapRef.current) {
      const show = checked ? checkWrapRef.current : xWrapRef.current;
      const hide = checked ? xWrapRef.current : checkWrapRef.current;
      activeTweens.current.push(
        gsap.to(hide, {
          rotateY: 90,
          autoAlpha: 0,
          duration: 0.18,
          ease: "power2.in",
        }),
      );
      activeTweens.current.push(
        gsap.fromTo(
          show,
          { rotateY: -90, autoAlpha: 0 },
          {
            rotateY: 0,
            autoAlpha: 1,
            duration: 0.32,
            ease: "back.out(2)",
            delay: 0.16,
          },
        ),
      );
    }
  }, [checked, TRAVEL, withIcon]);

  useEffect(() => {
    return () => {
      activeTweens.current.forEach((t) => t.kill());
      activeTweens.current = [];
    };
  }, []);

  return (
    <label
      htmlFor={id}
      className="group/switch flex max-w-fit cursor-pointer select-none items-center"
    >
      <div className="relative">
        <input
          type="checkbox"
          name={name}
          onToggle={onToggle}
          onChange={onChange}
          id={id}
          className="peer sr-only"
          checked={checked}
          data-cy={dataCy}
        />

        {/* Track */}
        <div
          ref={trackRef}
          className={cn(
            "h-8 w-14 origin-center rounded-full bg-gradient-to-br from-gray-3 to-gray-4 shadow-[inset_0_1px_2px_rgba(0,0,0,0.12)] transition-[background-image,box-shadow] duration-300 dark:from-[#5A616B] dark:to-[#3F4651]",
            "peer-checked:bg-gradient-to-br peer-checked:from-primary peer-checked:to-primary/80 peer-checked:shadow-[0_0_0_4px_rgba(91,93,185,0.18),inset_0_1px_2px_rgba(0,0,0,0.12)] peer-focus-visible:ring-2 peer-focus-visible:ring-primary/40",
            "group-active/switch:scale-[0.97]",
            isSm && "h-5",
            isDark &&
              "from-[#212B36] to-[#0F1620] dark:from-primary dark:to-primary/80",
          )}
        />

        {/* Glow burst (only fires when turning ON) */}
        <div
          ref={glowRef}
          className="pointer-events-none absolute inset-0 rounded-full bg-primary opacity-0"
          style={{ filter: "blur(10px)" }}
        />

        {/* Thumb */}
        <div
          ref={thumbRef}
          className={cn(
            "pointer-events-none absolute left-1 top-1 flex size-6 items-center justify-center rounded-full bg-gradient-to-br from-white to-gray-2 shadow-switch-1 ring-1 ring-black/5",
            "peer-checked:from-white peer-checked:to-white peer-checked:shadow-[0_2px_6px_rgba(0,0,0,0.18),0_0_0_1px_rgba(91,93,185,0.25)]",
            "group-active/switch:scale-95",
            isSm && "-top-1 left-0 size-7 shadow-switch-2",
          )}
          style={{ perspective: 400 }}
        >
          {withIcon && (
            <>
              <span
                ref={checkWrapRef}
                className="absolute inline-flex items-center justify-center"
                style={{ transformStyle: "preserve-3d", backfaceVisibility: "hidden" }}
              >
                <CheckIcon className="h-3 w-3 fill-primary text-primary" />
              </span>
              <span
                ref={xWrapRef}
                className="absolute inline-flex items-center justify-center"
                style={{ transformStyle: "preserve-3d", backfaceVisibility: "hidden" }}
              >
                <XIcon className="h-3 w-3 text-gray-5" />
              </span>
            </>
          )}
        </div>
      </div>
    </label>
  );
}
