import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from "react";
import { cx } from "../lib/cx";

export type ButtonVariant = "primary" | "secondary" | "fab";

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: ButtonVariant;
  loading?: boolean;
  /** Required for `variant="fab"` — icon-only, no visible label. */
  icon?: ReactNode;
}

function Spinner({ dark = false }: { dark?: boolean }) {
  return (
    <span
      aria-hidden
      className={cx(
        "inline-block h-4 w-4 animate-spin rounded-full border-2",
        dark ? "border-[var(--ink)]/25 border-t-[var(--ink)]" : "border-white/40 border-t-white"
      )}
    />
  );
}

/**
 * Shared press behavior: 1px downward shift + swap from elevated to an
 * inset shadow + slight darkening. This is what actually reads as
 * "physically pushed in" — scale alone doesn't sell it, the inset shadow
 * does the work.
 */
const pressable = cx(
  "elevation-transition active:translate-y-px active:brightness-95",
  "shadow-[var(--shadow-elevated)] active:shadow-[var(--shadow-pressed)]"
);

const base = cx(
  "relative inline-flex items-center justify-center gap-2",
  "font-body font-bold no-select [-webkit-tap-highlight-color:transparent]",
  "disabled:opacity-40 disabled:pointer-events-none disabled:active:translate-y-0 disabled:active:shadow-[var(--shadow-elevated)]"
);

/**
 * Touch-optimized button set. All variants meet the 48px minimum touch target.
 *
 * Text color rule: our brand action gradients (lime→teal, coral→amber) are
 * light/high-luminance by design — see theme.css. Buttons use --ink text on
 * them, not white, to stay at WCAG AA without a text-shadow crutch. The
 * `secondary` variant uses --ink for the same reason (low-transparency
 * surface fill, not a dark background).
 */
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ variant = "primary", loading = false, disabled, icon, className, children, ...props }, ref) => {
    const isDisabled = disabled || loading;

    if (variant === "fab") {
      return (
        <button
          ref={ref}
          disabled={isDisabled}
          className={cx(base, pressable, "h-14 w-14 rounded-full text-[var(--ink)]", className)}
          style={{ backgroundImage: "var(--gradient-accent)" }}
          {...props}
        >
          {loading ? <Spinner dark /> : icon ?? children}
        </button>
      );
    }

    if (variant === "secondary") {
      return (
        <button
          ref={ref}
          disabled={isDisabled}
          className={cx(
            base,
            pressable,
            "min-h-[48px] overflow-hidden rounded-2xl px-6 text-[var(--ink)]",
            className
          )}
          {...props}
        >
          <span
            className="absolute inset-0 rounded-2xl"
            style={{
              background: "var(--glass-fill)",
              backdropFilter: "blur(var(--glass-blur))",
              WebkitBackdropFilter: "blur(var(--glass-blur))",
            }}
          />
          <span className="glass-border pointer-events-none absolute inset-0 rounded-2xl" />
          <span className="relative z-10 flex items-center gap-2">
            {loading ? <Spinner dark /> : children}
          </span>
        </button>
      );
    }

    // primary
    return (
      <button
        ref={ref}
        disabled={isDisabled}
        className={cx(base, pressable, "min-h-[48px] rounded-2xl px-6 text-[var(--ink)]", className)}
        style={{ backgroundImage: "var(--gradient-primary)" }}
        {...props}
      >
        {loading ? <Spinner dark /> : children}
      </button>
    );
  }
);
Button.displayName = "Button";
