/**
 * Button Component
 *
 * 🔒 STYLE LOCKED - See DESIGN_SYSTEM.md for available variants and sizes.
 * Do not modify variants or add new ones without updating DESIGN_SYSTEM.md first.
 */
import { ReactNode, forwardRef } from "react";
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
import { Link } from "react-router-dom";

type ButtonSize = "xs" | "sm" | "md" | "lg";
type ButtonVariant = "solid" | "soft" | "outline" | "ghost" | "gradient";
type ButtonTone = "brand" | "success" | "warning" | "danger" | "neutral";
type ButtonShape = "rounded" | "pill";
type ButtonElement = HTMLButtonElement | HTMLAnchorElement;

interface ButtonProps {
  children: ReactNode; // Button text or content
  size?: ButtonSize; // Button size
  variant?: ButtonVariant; // Visual variant
  tone?: ButtonTone; // Color tone
  shape?: ButtonShape; // Border radius style
  startIcon?: ReactNode; // Icon before the text
  endIcon?: ReactNode; // Icon after the text
  onClick?: () => void; // Click handler
  disabled?: boolean; // Disabled state
  fullWidth?: boolean; // Stretch to parent width
  className?: string; // Additional classes
  type?: "button" | "submit" | "reset"; // Button type
  as?: "button" | "a" | typeof Link;
  href?: string;
  to?: string; // For React Router Link
  target?: string;
  rel?: string;
}

const toneMap: Record<
  ButtonTone,
  {
    solid: string;
    soft: string;
    outline: string;
    ghost: string;
    ring: string;
  }
> = {
  brand: {
    solid: "bg-brand-500 text-white hover:bg-brand-600",
    soft: "bg-brand-50 text-brand-600 hover:bg-brand-100",
    outline:
      "text-brand-600 ring-1 ring-brand-200 hover:bg-brand-25 dark:ring-brand-500/40 dark:text-brand-300 dark:hover:bg-brand-500/[0.08]",
    ghost:
      "text-brand-600 hover:bg-brand-50 dark:text-brand-300 dark:hover:bg-brand-500/[0.08]",
    ring: "focus-visible:ring-brand-500",
  },
  success: {
    solid: "bg-success-500 text-white hover:bg-success-600",
    soft: "bg-success-50 text-success-600 hover:bg-success-100",
    outline:
      "text-success-600 ring-1 ring-success-200 hover:bg-success-25 dark:ring-success-500/40 dark:text-success-300",
    ghost:
      "text-success-600 hover:bg-success-50 dark:text-success-300 dark:hover:bg-success-500/[0.08]",
    ring: "focus-visible:ring-success-500",
  },
  warning: {
    solid: "bg-warning-500 text-white hover:bg-warning-600",
    soft: "bg-warning-50 text-warning-600 hover:bg-warning-100",
    outline:
      "text-warning-600 ring-1 ring-warning-200 hover:bg-warning-25 dark:ring-warning-500/40 dark:text-warning-300",
    ghost:
      "text-warning-600 hover:bg-warning-50 dark:text-warning-300 dark:hover:bg-warning-500/[0.08]",
    ring: "focus-visible:ring-warning-500",
  },
  danger: {
    solid: "bg-error-500 text-white hover:bg-error-600",
    soft: "bg-error-50 text-error-600 hover:bg-error-100",
    outline:
      "text-error-600 ring-1 ring-error-200 hover:bg-error-25 dark:ring-error-500/40 dark:text-error-300",
    ghost:
      "text-error-600 hover:bg-error-50 dark:text-error-300 dark:hover:bg-error-500/[0.08]",
    ring: "focus-visible:ring-error-500",
  },
  neutral: {
    solid:
      "bg-gray-900 text-white hover:bg-gray-800 dark:bg-white/10 dark:hover:bg-white/20",
    soft:
      "bg-gray-100 text-gray-900 hover:bg-gray-200 dark:bg-white/[0.08] dark:text-white dark:hover:bg-white/[0.12]",
    outline:
      "text-gray-700 ring-1 ring-gray-300 hover:bg-gray-50 dark:text-gray-200 dark:ring-white/[0.08] dark:hover:bg-white/[0.04]",
    ghost:
      "text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-white/[0.04]",
    ring: "focus-visible:ring-gray-400",
  },
};

const gradientTone: Record<ButtonTone, string> = {
  brand:
    "text-white shadow-[0_20px_45px_-30px_rgba(6,147,227,0.9)] bg-[linear-gradient(135deg,var(--color-primary)_0%,var(--color-primary-dark)_100%)]",
  success:
    "text-white shadow-[0_20px_45px_-30px_rgba(11,191,135,0.9)] bg-[linear-gradient(135deg,var(--color-success)_0%,var(--color-success-dark)_100%)]",
  warning:
    "text-white shadow-[0_20px_45px_-30px_rgba(255,122,0,0.9)] bg-[linear-gradient(135deg,var(--color-warning)_0%,var(--color-warning-dark)_100%)]",
  danger:
    "text-white shadow-[0_20px_45px_-30px_rgba(239,68,68,0.9)] bg-[linear-gradient(135deg,var(--color-danger)_0%,var(--color-danger-dark)_100%)]",
  neutral:
    "text-white shadow-theme-lg bg-[linear-gradient(135deg,#0f172a,#1e293b)]",
};

const sizeClasses: Record<ButtonSize, string> = {
  xs: "h-7 px-2.5 text-xs",
  sm: "h-9 px-3 text-sm",
  md: "h-10 px-4 text-sm",
  lg: "h-12 px-5 text-base",
};

const Button = forwardRef<ButtonElement, ButtonProps>(
  (
    {
      children,
      size = "md",
      variant = "solid",
      tone = "brand",
      shape = "rounded",
      startIcon,
      endIcon,
      onClick,
      className = "",
      disabled = false,
      fullWidth = false,
      type = "button",
      as = "button",
      href,
      to,
      target,
      rel,
    },
    ref,
  ) => {
    const toneStyles = toneMap[tone];

    const variantClasses: Record<ButtonVariant, string> = {
      solid: toneStyles.solid,
      soft: toneStyles.soft,
      outline: clsx(
        "bg-transparent transition-colors",
        toneStyles.outline,
        "dark:bg-transparent",
      ),
      ghost: toneStyles.ghost,
      gradient: gradientTone[tone],
    };

    const baseClasses =
      "inline-flex items-center justify-center gap-2 font-medium transition duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed";

    const shapeClasses =
      shape === "pill" ? "rounded-full" : "rounded-lg";

    const ringClass = variant === "gradient" ? "focus-visible:ring-white/70" : toneStyles.ring;

    const computedClass = twMerge(
      clsx(
        baseClasses,
        sizeClasses[size],
        shapeClasses,
        variantClasses[variant],
        ringClass,
        {
          "w-full": fullWidth,
        },
        className,
      ),
    );

    const Component = as === "a" ? "a" : as === Link ? Link : "button";

    return (
      <Component
        ref={ref}
        className={computedClass}
        onClick={onClick}
        {...(as === "button"
          ? {
              type,
              disabled,
            }
          : as === Link
          ? {
              to,
              "aria-disabled": disabled,
            }
          : {
              href,
              target,
              rel,
              "aria-disabled": disabled,
            })}
      >
        {startIcon && <span className="flex items-center">{startIcon}</span>}
        <span className="whitespace-nowrap">{children}</span>
        {endIcon && <span className="flex items-center">{endIcon}</span>}
      </Component>
    );
  },
);

Button.displayName = "Button";

export default Button;
