"use client"

import * as React from "react"

import {
  Combobox,
  ComboboxContent,
  ComboboxEmpty,
  ComboboxInput,
  ComboboxItem,
  ComboboxList,
} from "@/components/ui/combobox"
import type { Choice } from "@/lib/choice"

/**
 * Picking one thing out of a long list of people or positions.
 *
 * It lives here rather than beside a form because two screens ask the same
 * question of the same roster: `/tasks/new` names a position, a checker and a
 * verifier, and `/positions/[id]` names a stand-in. A second copy would be a
 * second copy of the two decisions below, and both of them are the kind that is
 * quietly wrong in the copy nobody re-read.
 */

/**
 * The combobox searches and stores strings, and the database needs ids, so one
 * has to be turned into the other. The displayed string carries the hint
 * because titles and names repeat: an admin picking from 193 positions sees
 * "หัวหน้างาน (Supervisor)" more than once, and the department is the only thing
 * that tells two of them apart. A label that cannot be told apart is a label
 * somebody will choose wrongly.
 */
function labelled(choices: Choice[]) {
  const items = choices.map((c) =>
    c.hint ? `${c.label} · ${c.hint}` : c.label,
  )
  const idOf = new Map(choices.map((c, i) => [items[i]!, c.id]))
  const labelOf = new Map(choices.map((c, i) => [c.id, items[i]!]))
  return { items, idOf, labelOf }
}

export function ChoicePicker({
  id,
  value,
  onChange,
  choices,
  placeholder,
  empty,
}: {
  /**
   * Put on the text box and not on the combobox around it. The text box is the
   * control, so it is the thing a `<label for>` can name, and a combobox
   * announced by its placeholder is a combobox with no name at all the moment
   * somebody types.
   */
  id: string
  /** The id, which is what leaves this component. */
  value: string
  onChange: (id: string) => void
  choices: Choice[]
  placeholder: string
  empty: string
}) {
  const { items, idOf, labelOf } = React.useMemo(
    () => labelled(choices),
    [choices],
  )
  return (
    <Combobox
      items={items}
      value={(value && labelOf.get(value)) || null}
      onValueChange={(v) => onChange((v && idOf.get(v)) || "")}
    >
      <ComboboxInput id={id} placeholder={placeholder} className="w-full" />
      <ComboboxContent>
        <ComboboxEmpty>{empty}</ComboboxEmpty>
        <ComboboxList>
          {(name: string) => (
            <ComboboxItem key={name} value={name}>
              {name}
            </ComboboxItem>
          )}
        </ComboboxList>
      </ComboboxContent>
    </Combobox>
  )
}
