import type { ButtonHTMLAttributes, AnchorHTMLAttributes, ReactNode } from "react";

type ButtonTone = "primary" | "secondary" | "ghost";

type BaseProps = {
  children: ReactNode;
  className?: string;
  tone?: ButtonTone;
  /** Accessible label for screen readers (overrides children text) */
  "aria-label"?: string;
  /** Indicates if this button is part of a larger grouping */
  "aria-haspopup"?: boolean | "menu" | "listbox" | "tree" | "grid" | "dialog";
  /** Identifies the element controlled by this button */
  "aria-controls"?: string;
  /** Identifies the expanded state (for toggle buttons) */
  "aria-expanded"?: boolean;
  /** Identifies the pressed state (for toggle buttons) */
  "aria-pressed"?: boolean;
  /** Keyboard navigation: explicit tab index */
  tabIndex?: number;
};

type NativeButtonProps = BaseProps &
  ButtonHTMLAttributes<HTMLButtonElement> & {
    href?: never;
    to?: never;
  };

type AnchorButtonProps = BaseProps &
  AnchorHTMLAttributes<HTMLAnchorElement> & {
    href: string;
    to?: never;
  };

/**
 * Button component with accessibility support and multiple visual tones.
 *
 * Can be rendered as:
 * - `<button>` (default)
 * - `<a>` (when `href` is provided)
 *
 * Note: For React Router links, use the ButtonAsLink component instead.
 *
 * @example
 * // Native button
 * <Button tone="primary" onClick={handleClick}>Click me</Button>
 *
 * @example
 * // External link
 * <Button href="https://example.com" tone="secondary">External</Button>
 */
export type ButtonProps = NativeButtonProps | AnchorButtonProps;

const tones: Record<ButtonTone, string> = {
  primary: "border-accent bg-accent text-bg hover:bg-accent-hover focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-bg",
  secondary: "border-border bg-surface-raised text-fg hover:border-border-light hover:bg-surface-hover focus-visible:ring-2 focus-visible:ring-border focus-visible:ring-offset-2 focus-visible:ring-offset-bg",
  ghost: "border-transparent bg-transparent text-cyan hover:border-border-light hover:bg-surface focus-visible:ring-2 focus-visible:ring-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-bg",
};

/**
 * Shared button styles and accessibility support.
 * Used by both Button and ButtonAsLink components.
 */
export function useButtonProps(tone: ButtonTone = "secondary", className: string = "") {
  return [
    "inline-flex min-h-10 cursor-pointer items-center justify-center gap-2 rounded-md border px-4 py-2 text-sm font-semibold transition-colors duration-150 disabled:cursor-not-allowed disabled:opacity-55",
    "focus-visible:outline-none",
    tones[tone],
    className,
  ]
    .filter(Boolean)
    .join(" ");
}

export function Button({ children, className = "", tone = "secondary", ...props }: ButtonProps) {
  const classes = useButtonProps(tone, className);

  // Extract accessibility props to spread on the rendered element
  const { "aria-label": ariaLabel, "aria-haspopup": ariaHaspopup, "aria-controls": ariaControls, "aria-expanded": ariaExpanded, "aria-pressed": ariaPressed, tabIndex, ...restProps } = props;
  const ariaProps = { "aria-label": ariaLabel, "aria-haspopup": ariaHaspopup, "aria-controls": ariaControls, "aria-expanded": ariaExpanded, "aria-pressed": ariaPressed, tabIndex };

  // Handle native anchor (href prop)
  if ("href" in restProps && restProps.href) {
    const anchorProps = restProps as Omit<AnchorButtonProps, keyof BaseProps>;

    return (
      <a className={classes} {...anchorProps} {...ariaProps}>
        {children}
      </a>
    );
  }

  // Handle native button
  const buttonProps = restProps as Omit<NativeButtonProps, keyof BaseProps>;

  return (
    <button className={classes} type="button" {...buttonProps} {...ariaProps}>
      {children}
    </button>
  );
}
