import React from "react";
import { cn } from "@/lib/utils";
import { ButtonProps, ButtonRipple } from "@/types/external/shadcn";
import { MouseEvent, useCallback, useEffect, useState } from "react";
import { renderDecorator } from "./_util";
import variants from "./_variants";

const Button = ({
  className,
  pClassName,
  variant,
  color,
  size,
  decorator,
  isIcon = false,
  rounded = false,
  ...props
}: React.ComponentProps<"button"> & ButtonProps<typeof variants>) => {
  const [ripples, setRipples] = useState<ButtonRipple[]>([]);

  const createRiple = useCallback((event: MouseEvent<HTMLDivElement>) => {
    const button = event.currentTarget;
    const rect = button.getBoundingClientRect();
    const ripple: ButtonRipple = {
      id: Date.now(),
      x: event.clientX - rect.left,
      y: event.clientY - rect.top,
    };

    setRipples((prev) => [...prev, ripple]);
  }, []);

  useEffect(() => {
    const timer = setTimeout(() => {
      if (ripples.length > 0) {
        setRipples((prev) => prev.filter((e) => e.id !== ripples[0].id));
      }
    }, 600);

    return () => clearTimeout(timer);
  }, [ripples]);

  const handleClick = (event: MouseEvent<HTMLDivElement>) => {
    if (props.disabled) return;
    createRiple(event);
  };

  const handleContextMenu = (event: MouseEvent<HTMLDivElement>) => {
    if (props.disabled) return;
    createRiple(event);
  };

  return (
    <div
      className={cn("inline-flex", pClassName)}
      onClick={handleClick}
      onContextMenu={handleContextMenu}
    >
      <button
        className={cn(
          variants({ variant, color, size, isIcon, rounded, className }),
        )}
        type={props.type ?? "button"}
        {...props}
      >
        {renderDecorator("start", decorator, !!props.children)}
        {props.children}
        {renderDecorator("end", decorator, !!props.children)}
        {ripples.map((ripple) => (
          <span
            key={ripple.id}
            className="ripple"
            style={{
              position: "absolute",
              left: ripple.x,
              top: ripple.y,
              transform: "translate(-50%, -50%)",
              minHeight: "300%",
              minWidth: "300%",
              aspectRatio: "1 / 1",
              borderRadius: "50%",
              opacity: 0,
              pointerEvents: "none",
              animation: "ripple 600ms ease-out",
            }}
          />
        ))}
      </button>
    </div>
  );
};
Button.displayName = "Button";

export { Button };
