"use client";

import { useEffect, useId, useRef, useState } from "react";
import { FOCUS_RING_CLASSES } from "@/components/ui/styles";
import { cn } from "@/lib/utils";

export interface FilterSelectOption {
  value: string;
  label: string;
}

/**
 * Drop-in replacement for a native <select> inside a plain <form method="get">
 * GET filter bar — renders a hidden input carrying `name`/value so the
 * surrounding form submission (query params) is unchanged, while the visible
 * control is a custom-styled listbox (WAI-ARIA "Listbox Button" pattern)
 * instead of the unstylable native <select> popover.
 */
export function FilterSelect({
  name,
  options,
  defaultValue,
  ariaLabel,
  className = "",
}: {
  name: string;
  options: FilterSelectOption[];
  defaultValue?: string;
  ariaLabel: string;
  className?: string;
}) {
  const [value, setValue] = useState(defaultValue ?? options[0]?.value ?? "");
  const [open, setOpen] = useState(false);
  const rootRef = useRef<HTMLDivElement>(null);
  const triggerRef = useRef<HTMLButtonElement>(null);
  const listboxId = useId();

  const selectedIndex = Math.max(
    0,
    options.findIndex((o) => o.value === value),
  );
  const selectedLabel = options[selectedIndex]?.label ?? "";

  useEffect(() => {
    if (!open) return;
    function handlePointerDown(e: MouseEvent) {
      if (rootRef.current && !rootRef.current.contains(e.target as Node)) setOpen(false);
    }
    document.addEventListener("mousedown", handlePointerDown);
    return () => document.removeEventListener("mousedown", handlePointerDown);
  }, [open]);

  function handleTriggerKeyDown(e: React.KeyboardEvent) {
    if (e.key === "ArrowDown" || e.key === "ArrowUp") {
      e.preventDefault();
      setOpen(true);
    }
  }

  return (
    <div ref={rootRef} className={`relative ${className}`}>
      <input type="hidden" name={name} value={value} />
      <button
        ref={triggerRef}
        type="button"
        aria-haspopup="listbox"
        aria-expanded={open}
        aria-label={ariaLabel}
        onClick={() => setOpen((v) => !v)}
        onKeyDown={handleTriggerKeyDown}
        className={cn(
          "flex h-11 items-center justify-between gap-2 rounded-lg border border-kolabora-neutral-dark/20 bg-kolabora-neutral-white px-4 py-2.5 text-sm font-medium leading-none text-kolabora-neutral-dark transition-colors hover:border-kolabora-neutral-dark/30",
          FOCUS_RING_CLASSES,
        )}
      >
        <span>{selectedLabel}</span>
        <svg
          width="16"
          height="16"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
          aria-hidden="true"
          className={`shrink-0 text-kolabora-neutral-dark/50 transition-transform duration-150 ${open ? "rotate-180" : ""}`}
        >
          <path d="M6 9l6 6 6-6" />
        </svg>
      </button>

      {open && (
        <Listbox
          listboxId={listboxId}
          ariaLabel={ariaLabel}
          options={options}
          value={value}
          initialActiveIndex={selectedIndex}
          onCommit={(opt) => {
            setValue(opt.value);
            setOpen(false);
            triggerRef.current?.focus();
          }}
          onClose={() => {
            setOpen(false);
            triggerRef.current?.focus();
          }}
          onDismiss={() => setOpen(false)}
        />
      )}
    </div>
  );
}

/**
 * Only ever mounted while the trigger is open — a fresh instance each time,
 * so "reset active index" / "animate in" are just mount-time initialization,
 * not effects reacting to a prop change (see react-hooks/set-state-in-effect).
 */
function Listbox({
  listboxId,
  ariaLabel,
  options,
  value,
  initialActiveIndex,
  onCommit,
  onClose,
  onDismiss,
}: {
  listboxId: string;
  ariaLabel: string;
  options: FilterSelectOption[];
  value: string;
  initialActiveIndex: number;
  onCommit: (option: FilterSelectOption) => void;
  onClose: () => void;
  onDismiss: () => void;
}) {
  const [activeIndex, setActiveIndex] = useState(initialActiveIndex);
  const [entered, setEntered] = useState(false);
  const listRef = useRef<HTMLUListElement>(null);

  useEffect(() => {
    listRef.current?.focus();
    const id = requestAnimationFrame(() => setEntered(true));
    return () => cancelAnimationFrame(id);
  }, []);

  function handleKeyDown(e: React.KeyboardEvent) {
    switch (e.key) {
      case "ArrowDown":
        e.preventDefault();
        setActiveIndex((i) => Math.min(options.length - 1, i + 1));
        break;
      case "ArrowUp":
        e.preventDefault();
        setActiveIndex((i) => Math.max(0, i - 1));
        break;
      case "Home":
        e.preventDefault();
        setActiveIndex(0);
        break;
      case "End":
        e.preventDefault();
        setActiveIndex(options.length - 1);
        break;
      case "Enter":
      case " ":
        e.preventDefault();
        if (options[activeIndex]) onCommit(options[activeIndex]);
        break;
      case "Escape":
        e.preventDefault();
        onClose();
        break;
      case "Tab":
        onDismiss();
        break;
    }
  }

  return (
    <ul
      ref={listRef}
      id={listboxId}
      role="listbox"
      tabIndex={-1}
      aria-activedescendant={`${listboxId}-option-${activeIndex}`}
      aria-label={ariaLabel}
      onKeyDown={handleKeyDown}
      className={`absolute left-0 right-0 top-full z-20 mt-1 max-h-72 overflow-auto rounded-xl border border-kolabora-neutral-dark/10 bg-kolabora-neutral-white p-1.5 shadow-lg transition duration-150 ease-out focus:outline-none ${
        entered ? "scale-100 opacity-100" : "scale-95 opacity-0"
      }`}
    >
      {options.map((opt, i) => {
        const isSelected = opt.value === value;
        const isActive = i === activeIndex;
        return (
          <li
            key={opt.value}
            id={`${listboxId}-option-${i}`}
            role="option"
            aria-selected={isSelected}
            onMouseEnter={() => setActiveIndex(i)}
            onClick={() => onCommit(opt)}
            className={`flex min-h-10 cursor-pointer items-center rounded-lg px-3 py-2 text-sm font-medium leading-snug transition-colors duration-150 ${
              isSelected
                ? "bg-kolabora-primary/10 text-kolabora-primary"
                : isActive
                  ? "bg-kolabora-neutral-dark/5 text-kolabora-neutral-dark"
                  : "text-kolabora-neutral-dark"
            }`}
          >
            {opt.label}
          </li>
        );
      })}
    </ul>
  );
}
