import { useState } from "react";
import { Check, ChevronDown, type LucideIcon } from "lucide-react";
import clsx from "clsx";
import { PopoverItem, PopoverSurface, useAnchoredPopover } from "./AnchoredPopover";

export interface ViewOption<T extends string> {
  id: T;
  label: string;
  icon: LucideIcon;
}

// "How should this list look" — the current mode's icon in the toolbar, the named modes in a
// menu behind it. Generic over the mode id so any module's list can adopt it (the feed's
// density modes; the managers' layouts) without re-deriving the menu behaviour.
//
// This was the house's textbook menu, with its own hand-rolled roving-tabindex/arrow/Escape engine.
// It now rides the R8 popover platform like every other menu, which supplies the same model
// (arrows/Home/End rove, Escape closes and hands focus back to the trigger, Tab out closes) plus the
// two things the hand-rolled version lacked: typeahead, and anchoring that flips and shifts instead
// of being absolutely positioned inside whatever ancestor happens to clip it.
export default function ViewSwitcher<T extends string>({
  value,
  options,
  onChange,
  label,
  labelClassName = "hidden",
}: {
  value: T;
  options: readonly ViewOption<T>[];
  onChange: (v: T) => void;
  label: string;
  /** Where the current mode's NAME is visible beside the icon — a Tailwind display class, e.g.
   * `"hidden xl:inline"`. The caller sets it because only it knows how crowded its own toolbar is:
   * the feed's is packed (show chips, content chips, source, count, sort) and can't spare the room
   * until xl, while an emptier one could show it always. Defaults to icon-only. */
  labelClassName?: string;
}) {
  const [open, setOpen] = useState(false);

  // A `value` outside `options` is a caller bug; degrade to the first option rather than render
  // nothing. The menu then shows no checked item, which is honest — nothing IS selected.
  const currentIdx = Math.max(
    0,
    options.findIndex((o) => o.id === value),
  );

  const pop = useAnchoredPopover({
    open,
    onOpenChange: setOpen,
    placement: "bottom-end",
    // Opening a "pick one of these modes" menu should land on the mode that is already picked.
    selectedIndex: currentIdx,
  });

  const current = options[currentIdx];
  if (!current) return null;
  const CurrentIcon = current.icon;

  return (
    <>
      <button
        ref={pop.refs.setReference}
        {...pop.getReferenceProps()}
        // The aria-label carries the mode's name at every size — the visible text below is a
        // nicety for wide windows, not the accessible name.
        aria-label={`${label}: ${current.label}`}
        title={`${label}: ${current.label}`}
        className="shrink-0 inline-flex items-center gap-1 pl-2 pr-1 py-1.5 rounded-lg border border-border bg-card text-fg hover:border-accent hover:text-accent active:translate-y-px transition"
      >
        <CurrentIcon className="w-4 h-4 shrink-0" />
        <span className={clsx("text-sm whitespace-nowrap", labelClassName)}>{current.label}</span>
        <ChevronDown
          className={`w-3 h-3 shrink-0 transition-transform ${open ? "rotate-180" : ""}`}
        />
      </button>
      <PopoverSurface
        popover={pop}
        ariaLabel={label}
        className="glass-menu min-w-44 p-1.5 rounded-xl animate-[popIn_0.16s_ease]"
      >
        {/* The modes are one exclusive choice, so the radio items need a group to scope their
            checked-ness to — otherwise they read as independent checkable items. */}
        <div role="group">
          {options.map((o) => {
            const Icon = o.icon;
            const on = o.id === value;
            return (
              <PopoverItem
                key={o.id}
                role="menuitemradio"
                checked={on}
                onSelect={() => {
                  onChange(o.id);
                  setOpen(false);
                }}
                label={o.label}
                className={`w-full flex items-center gap-2 px-2 py-1.5 rounded-lg text-sm text-left outline-none transition data-[active]:bg-[color-mix(in_srgb,var(--accent)_24%,transparent)] ${
                  on ? "text-accent" : "text-fg hover:bg-card"
                }`}
              >
                <Icon className="w-4 h-4 shrink-0" />
                <span className="flex-1 truncate">{o.label}</span>
                {on && <Check className="w-3.5 h-3.5 shrink-0" />}
              </PopoverItem>
            );
          })}
        </div>
      </PopoverSurface>
    </>
  );
}
