"use client";

import * as React from "react";
import { useInView } from "framer-motion";

/**
 * GlitchText: Binary scramble reveal effect
 *
 * Text characters scramble through random binary (0/1) before settling
 * into the final text. Creates a "decoding" feel.
 *
 * Can also be triggered on hover for buttons.
 */

interface GlitchTextProps {
  children: string;
  className?: string;
  delay?: number;
  duration?: number;
  trigger?: "inView" | "hover" | "mount";
  as?: "span" | "div" | "h1" | "h2" | "p";
}

const CHARS = "01";

export const GlitchText: React.FC<GlitchTextProps> = ({
  children,
  className = "",
  delay = 0,
  duration = 0.8,
  trigger = "inView",
  as: Tag = "span",
}) => {
  const text = children;
  const [display, setDisplay] = React.useState(text);
  const [isRevealed, setIsRevealed] = React.useState(false);
  const [isHovering, setIsHovering] = React.useState(false);
  const ref = React.useRef<any>(null);
  const isInView = useInView(ref, { once: true, margin: "-10%" });

  // Initial scramble reveal (on mount or in-view)
  React.useEffect(() => {
    if (isRevealed) return;

    const shouldStart =
      trigger === "mount" || (trigger === "inView" && isInView);
    if (!shouldStart) return;

    const chars = text.split("");
    const totalFrames = Math.ceil(duration * 60); // ~60fps
    const staggerPerChar = totalFrames / chars.length;
    let frame = 0;

    const delayMs = delay * 1000;

    const timeout = setTimeout(() => {
      const interval = setInterval(() => {
        frame++;
        const revealed = chars.map((char, i) => {
          if (char === " ") return " ";
          const charFrame = i * staggerPerChar;
          if (frame > charFrame + staggerPerChar * 2) return char; // Settled
          if (frame > charFrame) {
            // Scrambling phase
            return CHARS[Math.floor(Math.random() * CHARS.length)];
          }
          return CHARS[Math.floor(Math.random() * CHARS.length)];
        });
        setDisplay(revealed.join(""));

        if (frame >= totalFrames + staggerPerChar * 2) {
          setDisplay(text);
          setIsRevealed(true);
          clearInterval(interval);
        }
      }, 1000 / 60);

      return () => clearInterval(interval);
    }, delayMs);

    return () => clearTimeout(timeout);
  }, [isInView, trigger, text, delay, duration, isRevealed]);

  // Hover re-scramble (for buttons)
  React.useEffect(() => {
    if (!isHovering || trigger !== "hover") return;

    const chars = text.split("");
    const totalFrames = 20; // Quick scramble
    let frame = 0;

    const interval = setInterval(() => {
      frame++;
      const scrambled = chars.map((char, i) => {
        if (char === " ") return " ";
        const settle = (frame / totalFrames) * chars.length;
        if (i < settle) return char;
        return CHARS[Math.floor(Math.random() * CHARS.length)];
      });
      setDisplay(scrambled.join(""));

      if (frame >= totalFrames) {
        setDisplay(text);
        clearInterval(interval);
      }
    }, 1000 / 60);

    return () => clearInterval(interval);
  }, [isHovering, trigger, text]);

  return (
    <Tag
      ref={ref}
      className={`${className}`}
      onMouseEnter={trigger === "hover" ? () => setIsHovering(true) : undefined}
      onMouseLeave={
        trigger === "hover" ? () => setIsHovering(false) : undefined
      }
      style={{ fontVariantNumeric: "tabular-nums" }} // Prevent layout shift during scramble
    >
      {display}
    </Tag>
  );
};
