"use client"

/**
 * AskLeoButton — chart-card Leo CTA (outline sm, duotone star + label).
 *
 * Default `onClick` toggles the Ask Leo sidebar (`useAskLeo`). Pass `onClick`
 * to override (e.g. inline draft on the new-question composer).
 *
 * @see charts-overview.tsx — ChartCard header (canonical usage)
 * @see AGENTS.md / charts-overview file header — Ask Leo icon guideline
 */

import * as React from "react"

import { AskLeoShortcutKbds, useAskLeo } from "@/components/ask-leo-context"
import { Button } from "@/components/ui/button"
import {
  LeoIcon,
  type LeoIconMotionState,
  type LeoIconSize,
} from "@/components/ui/leo-icon"
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip"
import { cn } from "@/lib/utils"

export interface AskLeoButtonProps {
  /** Matches chart card header (`sm`) or page header actions (`lg`, e.g. Save question). */
  size?: "sm" | "lg"
  /** When true, hides the text label (chart selector variant). */
  iconOnly?: boolean
  /** Button label. Default `"Ask Leo"`. */
  label?: string
  /** Overrides sidebar toggle — use for route-local Leo actions. */
  onClick?: () => void
  disabled?: boolean
  "aria-busy"?: boolean
  /** Accessible name; defaults to `label`. */
  ariaLabel?: string
  /** Shown instead of `label` when `aria-busy` is true. */
  busyLabel?: string
  /** Tooltip body before shortcut chips. Defaults to `label`. */
  tooltipLabel?: string
  /** When false, tooltip omits ⌘⌥K hints (non-sidebar actions). Default true. */
  showShortcut?: boolean
  /**
   * Animated Leo star (`LeoIcon` ambient). Defaults to true when `size="lg"`.
   * Chart cards keep the static duotone glyph (`size="sm"`).
   */
  animatedStar?: boolean
  /**
   * Play one `invited` gesture when the button appears, then settle to `rest`.
   * For entry points that arrive unannounced (the floating launcher) rather
   * than ones the user already sees in a toolbar.
   */
  introduceOnMount?: boolean
  /**
   * `brand` fills the surface with the brand colour and flips the star to
   * `--brand-foreground`. Paired here rather than left to callers so the star
   * can never end up brand-on-brand.
   */
  tone?: "default" | "brand"
  /** Star box. Defaults to `xs` (20px), which fits the `sm` / `lg` buttons. */
  starSize?: LeoIconSize
  className?: string
}

export function AskLeoButton({
  size = "sm",
  iconOnly = false,
  label = "Ask Leo",
  onClick: onClickProp,
  disabled = false,
  "aria-busy": ariaBusy,
  ariaLabel,
  busyLabel,
  tooltipLabel,
  showShortcut = true,
  animatedStar,
  introduceOnMount = false,
  tone = "default",
  starSize = "xs",
  className,
}: AskLeoButtonProps) {
  const { toggle } = useAskLeo()
  const displayLabel = ariaBusy && busyLabel ? busyLabel : label
  const tipText = tooltipLabel ?? label
  const useAnimatedStar = animatedStar ?? size === "lg"

  // Dropping the label is not enough to make a square trigger: the text sizes
  // keep their inline padding, which left `lg` iconOnly as a 70x40 pill with a
  // floating star. Switch to the aspect-square icon sizes instead.
  const buttonSize = iconOnly ? (size === "lg" ? "icon-lg" : "icon-sm") : size

  const leoFillClass =
    tone === "brand"
      ? // On a brand fill the star has to be the on-brand foreground, not a
        // brand shade — brand-on-brand would disappear.
        "[--leo-icon-fill:var(--brand-foreground)]"
      : "[--leo-icon-fill:var(--brand-color-dark)] dark:[--leo-icon-fill:var(--brand-color-light)]"

  const toneClass =
    tone === "brand"
      ? "border-transparent bg-brand text-brand-foreground hover:bg-brand/90 hover:text-brand-foreground dark:bg-brand dark:hover:bg-brand/90"
      : undefined

  // Pointer and keyboard both count as intent, so the star reacts for keyboard
  // users too rather than rewarding only the mouse.
  const [invited, setInvited] = React.useState(false)

  // `invited` is a one-shot gesture, so playing it once means holding the state
  // for its duration and then settling. Slightly longer than LEO_GESTURE (0.42s)
  // so the keyframes finish before the state changes under them.
  const [introducing, setIntroducing] = React.useState(introduceOnMount)
  React.useEffect(() => {
    if (!introducing) return
    const timer = window.setTimeout(() => setIntroducing(false), 520)
    return () => window.clearTimeout(timer)
  }, [introducing])

  const leoState: LeoIconMotionState = ariaBusy
    ? "working"
    : invited || introducing
      ? "invited"
      : "rest"

  const starMark = useAnimatedStar ? (
    <span
      aria-hidden
      className={cn(
        // No size of its own: `LeoIcon` already applies the box for whichever
        // `size` it was given, so hugging the glyph keeps the two in step. At
        // the `xs` default that is the same 20px box as before, which matches
        // the duotone glyph's optical weight and fits the 28px `sm` button.
        "relative inline-flex shrink-0 items-center justify-center overflow-visible",
        leoFillClass,
      )}
    >
      <LeoIcon
        variant="ambient"
        size={starSize}
        state={leoState}
        className="pointer-events-none overflow-visible"
      />
    </span>
  ) : (
    <i
      className={cn(
        "fa-duotone fa-solid fa-star-christmas text-[color:var(--brand-color-dark)] dark:text-[color:var(--brand-color-light)]",
        size === "lg" ? "text-sm" : "text-xs",
      )}
      aria-hidden="true"
    />
  )

  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <Button
          type="button"
          size={buttonSize}
          variant="outline"
          disabled={disabled}
          aria-busy={ariaBusy}
          className={cn(
            "shrink-0 gap-1.5",
            // `sm` sits a notch tighter than the shared Button `sm` so it can
            // ride inside a ChartCard header. Keep the square form at the same
            // 28px so both `sm` shapes line up in a toolbar.
            size === "sm" && (iconOnly ? "size-7 text-xs" : "h-7 px-2 text-xs"),
            useAnimatedStar && "overflow-visible",
            toneClass,
            className,
          )}
          aria-label={ariaLabel ?? displayLabel}
          onClick={onClickProp ?? toggle}
          onPointerEnter={() => setInvited(true)}
          onPointerLeave={() => setInvited(false)}
          onFocus={() => setInvited(true)}
          onBlur={() => setInvited(false)}
        >
          {starMark}
          {!iconOnly ? <span>{displayLabel}</span> : null}
        </Button>
      </TooltipTrigger>
      <TooltipContent side="bottom" className="flex flex-wrap items-center gap-1.5">
        <span>{tipText}</span>
        {showShortcut ? <AskLeoShortcutKbds /> : null}
      </TooltipContent>
    </Tooltip>
  )
}
