"use client";

import { useEffect, useId, useMemo, useRef, useState } from "react";
import { IconChevronDown, IconSearch } from "./icons";

const triggerClassName =
  "text-m-regular flex h-10 w-full items-center justify-between rounded-lg border border-neutral-40 bg-neutral-10 px-[22px] py-2 text-left text-neutral-100 outline-none focus:border-primary-500 disabled:cursor-not-allowed disabled:opacity-60";

export type FilterSearchSelectProps = {
  value: string;
  options: readonly string[];
  onChange: (value: string) => void;
  searchPlaceholder?: string;
  emptyMessage?: string;
  disabled?: boolean;
  className?: string;
};

export function FilterSearchSelect({
  value,
  options,
  onChange,
  searchPlaceholder = "Cari...",
  emptyMessage = "Tidak ada hasil.",
  disabled = false,
  className = "relative min-w-[180px] flex-1 max-w-[220px]",
}: FilterSearchSelectProps) {
  const listboxId = useId();
  const containerRef = useRef<HTMLDivElement>(null);
  const searchInputRef = useRef<HTMLInputElement>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");

  const filteredOptions = useMemo(() => {
    const query = searchQuery.trim().toLowerCase();

    if (!query) {
      return options;
    }

    return options.filter((option) =>
      option.toLowerCase().includes(query),
    );
  }, [options, searchQuery]);

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    function handleClickOutside(event: MouseEvent) {
      if (
        containerRef.current &&
        !containerRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    }

    function handleEscape(event: KeyboardEvent) {
      if (event.key === "Escape") {
        setIsOpen(false);
      }
    }

    document.addEventListener("mousedown", handleClickOutside);
    document.addEventListener("keydown", handleEscape);

    const frameId = requestAnimationFrame(() => {
      searchInputRef.current?.focus();
    });

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
      document.removeEventListener("keydown", handleEscape);
      cancelAnimationFrame(frameId);
    };
  }, [isOpen]);

  function handleOpen() {
    if (disabled) {
      return;
    }

    setSearchQuery("");
    setIsOpen(true);
  }

  function handleSelect(option: string) {
    onChange(option);
    setIsOpen(false);
    setSearchQuery("");
  }

  return (
    <div ref={containerRef} className={className}>
      <button
        type="button"
        onClick={handleOpen}
        disabled={disabled}
        aria-expanded={isOpen}
        aria-haspopup="listbox"
        aria-controls={listboxId}
        className={triggerClassName}
      >
        <span className="truncate pr-2">{value}</span>
        <IconChevronDown className="size-5 shrink-0 text-neutral-100" />
      </button>

      {isOpen && (
        <div className="absolute top-[calc(100%+4px)] left-0 z-50 w-full overflow-hidden rounded-lg border border-neutral-40 bg-neutral-10 shadow-sm">
          <div className="border-b border-neutral-40 p-2">
            <div className="relative">
              <input
                ref={searchInputRef}
                type="search"
                value={searchQuery}
                onChange={(event) => setSearchQuery(event.target.value)}
                placeholder={searchPlaceholder}
                className="text-m-regular h-9 w-full rounded-lg border border-neutral-40 bg-neutral-10 px-3 py-2 pr-9 text-neutral-100 placeholder:text-neutral-70 outline-none focus:border-primary-500"
              />
              <IconSearch className="pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-neutral-70" />
            </div>
          </div>

          <ul
            id={listboxId}
            role="listbox"
            aria-label="Pilihan filter"
            className="max-h-56 overflow-y-auto py-1"
          >
            {filteredOptions.length === 0 ? (
              <li className="text-m-regular px-4 py-2 text-neutral-70">
                {emptyMessage}
              </li>
            ) : (
              filteredOptions.map((option) => {
                const isSelected = option === value;

                return (
                  <li key={option} role="option" aria-selected={isSelected}>
                    <button
                      type="button"
                      onClick={() => handleSelect(option)}
                      className={`text-m-regular w-full truncate px-4 py-2 text-left transition-colors hover:bg-neutral-20 ${
                        isSelected
                          ? "bg-primary-50 text-primary-700"
                          : "text-neutral-100"
                      }`}
                    >
                      {option}
                    </button>
                  </li>
                );
              })
            )}
          </ul>
        </div>
      )}
    </div>
  );
}
