"use client";

import { useMemo, useState } from "react";
import { Check, ChevronsUpDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Command, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Spinner } from "@/components/ui/spinner";
import { PickerCreateDialog, PickerFooter, createOnEnter, hasExactOption, matchOptions, usePickerCreate } from "@/components/app/picker-create";
import { cn } from "@/lib/utils";

/**
 * Searchable single select (Popover + Command). Works standalone (table rows) or through ComboboxField (forms).
 * options: [{ value, label, description? }].
 *
 * Pass `create` (from useQuickAdd in app/lib/useQuickAdd.js) so a missing option is never a dead end: the list ends
 * with "+ Add “…” as a new buyer" (Enter adds it when nothing matches), or says who can add it when this user may
 * not. `onCreate(label) => Promise<{ value, label }>` + `createNoun` is the short form for a name-only create.
 * `loading` (options still being fetched) shows "Loading…" instead of offering to add something that may exist.
 */
export function SearchableSelect({
  id, value, onChange, onBlur, options, placeholder = "Select…", searchPlaceholder = "Search…", emptyText = "No match.",
  allowEmpty = false, emptyLabel = "None", create, onCreate, createNoun, loading = false, disabled, invalid, size, className, "aria-label": ariaLabel,
}) {
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState("");
  // Options added here are kept so the new value shows its label before the caller's list reloads.
  const [added, setAdded] = useState([]);
  const config = useMemo(() => create || (onCreate ? { onCreate, noun: createNoun } : null), [create, onCreate, createNoun]);
  const allOptions = useMemo(() => [...added.filter((item) => !options.some((option) => String(option.value) === String(item.value))), ...options], [added, options]);
  const query = search.trim();
  const visible = useMemo(() => matchOptions(allOptions, query), [allOptions, query]);
  const selected = allOptions.find((option) => String(option.value) === String(value));
  const showNone = allowEmpty && !query;
  const count = visible.length;
  const isLoading = loading && allOptions.length === 0;

  const choose = (next) => {
    onChange(next);
    setOpen(false);
    setSearch("");
  };

  const creator = usePickerCreate(config, {
    closePicker: () => { setOpen(false); setSearch(""); },
    onCreated: (option) => {
      setAdded((current) => [option, ...current.filter((item) => String(item.value) !== String(option.value))]);
      choose(String(option.value));
    },
  });

  const emptyNote = query ? (emptyText === "No match." ? `Nothing matches “${query}”.` : emptyText) : allOptions.length ? emptyText : "Nothing to choose from yet.";

  return <>
    <Popover open={open} onOpenChange={(next) => { setOpen(next); if (!next) setSearch(""); }}>
      <PopoverTrigger asChild>
        <Button id={id} type="button" variant="outline" size={size} role="combobox" aria-expanded={open} aria-invalid={invalid} aria-label={ariaLabel} disabled={disabled} onBlur={onBlur}
          className={cn("w-full justify-between font-normal", !selected && "text-muted-foreground", invalid && "border-destructive", className)}>
          <span className="truncate">{selected?.label || (allowEmpty && !value ? emptyLabel : placeholder)}</span>
          <ChevronsUpDown className="opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-(--radix-popover-trigger-width) min-w-64 p-0" align="start">
        <Command shouldFilter={false}>
          <CommandInput placeholder={creator.enabled ? `${searchPlaceholder.replace(/…$/, "")} or type a new one…` : searchPlaceholder} value={search} onValueChange={setSearch}
            onKeyDown={(event) => createOnEnter(event, { creator, query, count, isLoading })} />
          <CommandList>
            {isLoading && <div className="flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground" role="status"><Spinner /> Loading…</div>}
            {(showNone || count > 0) && <CommandGroup>
              {showNone && <CommandItem value="__none" onSelect={() => choose("")}><Check className={cn(value ? "opacity-0" : "opacity-100")} />{emptyLabel}</CommandItem>}
              {visible.map((option) => <CommandItem key={option.value} value={String(option.value)} onSelect={() => choose(String(option.value))}>
                <Check className={cn(String(option.value) === String(value) ? "opacity-100" : "opacity-0")} />
                <span className="grid min-w-0"><span className="truncate">{option.label}</span>{option.description && <span className="truncate text-xs text-muted-foreground">{option.description}</span>}</span>
              </CommandItem>)}
            </CommandGroup>}
            <PickerFooter creator={creator} create={config} query={query} count={count} exactMatch={hasExactOption(allOptions, query)} emptyText={emptyNote} isLoading={isLoading} />
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
    {creator.enabled && <PickerCreateDialog creator={creator} />}
  </>;
}
