"use client";

import { useEffect, useRef, useState } from "react";

type Option = { value: string; label: string };

// A fully custom-styled dropdown — a native <select>'s trigger box can be
// styled, but its open options popup is rendered by the browser/OS itself
// and can't be reached with CSS at all (wrong font size, wrong colors, no
// brand styling whatsoever). This renders both the trigger and the
// options panel as plain HTML we control end to end. Originally built for
// /konto/bestellungen's filters, promoted to a shared component so
// checkout's country selects can use the same look (moved here 2026-07-30).
export function CustomSelect({
  label,
  options,
  value,
  onChange,
  includeAllOption = true,
  fullWidth = false,
}: {
  /** Screen-reader label — also the trigger's placeholder text when
   * `includeAllOption` is true and nothing is selected. */
  label: string;
  options: Option[];
  value: string;
  onChange: (value: string) => void;
  /** true (default): prepends a `{value: "", label}` "clear/show all"
   * pseudo-option — the filter-dropdown use case (Order/blog/etc.
   * filters), where "nothing selected" is a real, meaningful state.
   * false: no pseudo-option, every real option is selectable and one is
   * always genuinely selected — the plain-select-replacement use case
   * (e.g. checkout's country picker), where there's no "clear" concept. */
  includeAllOption?: boolean;
  /** false (default): trigger shrinks to its content width from sm: up —
   * right for a row of compact filter dropdowns. true: trigger always
   * stays full width of its container — right for a form-field
   * replacement (e.g. checkout's country picker, alongside other w-full
   * inputs). */
  fullWidth?: boolean;
}) {
  const [open, setOpen] = useState(false);
  const [highlighted, setHighlighted] = useState(0);
  const rootRef = useRef<HTMLDivElement>(null);
  const listRef = useRef<HTMLUListElement>(null);

  const allOptions: Option[] = includeAllOption ? [{ value: "", label }, ...options] : options;
  const selectedIndex = Math.max(
    0,
    allOptions.findIndex((o) => o.value === value),
  );
  const selectedLabel = allOptions[selectedIndex]?.label ?? label;

  useEffect(() => {
    if (!open) return;
    setHighlighted(selectedIndex);
    function onClickOutside(e: MouseEvent) {
      if (!rootRef.current?.contains(e.target as Node)) setOpen(false);
    }
    document.addEventListener("mousedown", onClickOutside);
    return () => document.removeEventListener("mousedown", onClickOutside);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open]);

  useEffect(() => {
    if (!open) return;
    listRef.current?.querySelector<HTMLElement>(`[data-index="${highlighted}"]`)?.scrollIntoView({ block: "nearest" });
  }, [open, highlighted]);

  // Keyboard/focus-driven close: Tabbing (or programmatically moving
  // focus) away from the trigger+list entirely used to leave the panel
  // open forever — the mousedown-outside listener above only ever reacts
  // to a mouse click, not focus leaving via Tab. `relatedTarget` is where
  // focus is headed; null on some browsers when it lands outside the
  // document/on a non-focusable element, which should also close.
  function onBlur(e: React.FocusEvent) {
    if (!rootRef.current?.contains(e.relatedTarget as Node)) setOpen(false);
  }

  function select(index: number) {
    onChange(allOptions[index].value);
    setOpen(false);
  }

  function onKeyDown(e: React.KeyboardEvent) {
    if (!open) {
      if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
        e.preventDefault();
        setOpen(true);
      }
      return;
    }
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setHighlighted((i) => Math.min(i + 1, allOptions.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setHighlighted((i) => Math.max(i - 1, 0));
    } else if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      select(highlighted);
    } else if (e.key === "Escape") {
      e.preventDefault();
      setOpen(false);
    }
  }

  return (
    <div ref={rootRef} onBlur={onBlur} className={`relative w-full ${fullWidth ? "" : "sm:w-auto"}`}>
      <button
        type="button"
        aria-haspopup="listbox"
        aria-expanded={open}
        aria-label={label}
        onClick={() => setOpen((v) => !v)}
        onKeyDown={onKeyDown}
        className={`flex items-center justify-between gap-2 w-full ${fullWidth ? "" : "sm:w-auto min-w-[10rem]"} border rounded-sm ${
          fullWidth ? "px-4 py-3" : "px-3 py-2"
        } text-body-sm transition-colors outline-none ${
          value ? "border-brand text-text-primary" : "border-border text-text-muted"
        } hover:border-brand focus-visible:border-brand`}
      >
        <span className="truncate">{selectedLabel}</span>
        <svg width="10" height="6" viewBox="0 0 10 6" fill="none" className={`shrink-0 transition-transform ${open ? "rotate-180" : ""}`}>
          <path d="M1 1L5 5L9 1" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </button>

      {open && (
        <ul
          ref={listRef}
          role="listbox"
          aria-label={label}
          // Without this, a mousedown on an <li> blurs the trigger button
          // first (li isn't focusable) — the resulting onBlur closes and
          // unmounts this list before the click event ever fires, so
          // nothing is ever selectable by mouse/touch.
          onMouseDown={(e) => e.preventDefault()}
          className="absolute z-20 mt-1 w-full sm:min-w-[12rem] max-h-64 overflow-y-auto bg-bg-base border border-border rounded-sm shadow-lg py-1"
        >
          {allOptions.map((o, i) => (
            <li
              key={o.value || "__all__"}
              data-index={i}
              role="option"
              aria-selected={i === selectedIndex}
              onMouseEnter={() => setHighlighted(i)}
              onClick={() => select(i)}
              className={`px-3 py-2 text-body-sm cursor-pointer transition-colors ${
                i === selectedIndex ? "font-semibold text-brand" : "text-text-primary"
              } ${i === highlighted ? "bg-bg-muted" : ""}`}
            >
              {o.label}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
