"use client";

import { useState, useEffect, useRef } from "react";
import { Combobox } from "@headlessui/react";
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid";
import { PRIMARY_COLOR } from "@/lib/common";

interface Option {
  label: string;
  value: string;
}

interface SearchableSelect2Props {
  label?: string;
  apiUrl?: string;
  /** When provided, skips the API fetch and uses these options directly. */
  staticOptions?: Option[];
  value?: Option | null;
  onChange: (value: Option | null) => void;
  placeholder?: string;
  error?: string;
  className?: string;
  autoComplete?: string;
  onBlur?: () => void;
  /** When this value changes, options are refetched from the API (e.g. after adding a new item). */
  refreshTrigger?: unknown;
}

const SearchableSelect2: React.FC<SearchableSelect2Props> = ({
  label,
  apiUrl,
  staticOptions,
  value,
  onChange,
  placeholder = "Select an option...",
  error,
  className = "",
  autoComplete = "off",
  onBlur,
  refreshTrigger,
}) => {
  const [query, setQuery] = useState("");
  const [options, setOptions] = useState<Option[]>(staticOptions ?? []);
  const [loading, setLoading] = useState(false);
  const buttonRef = useRef<HTMLButtonElement | null>(null);

  // Keep in sync when staticOptions change externally
  useEffect(() => {
    if (staticOptions) {
      setOptions(staticOptions);
    }
  }, [staticOptions]);

  useEffect(() => {
    if (staticOptions || !apiUrl) return;

    const controller = new AbortController();
    const fetchOptions = async () => {
      setLoading(true);
      try {
        const response = await fetch(apiUrl, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({}),
          cache: "no-store",
          credentials: "include",
          signal: controller.signal,
        });
        if (!response.ok) {
          throw new Error(`Failed to fetch options: ${response.status}`);
        }
        const data = await response.json();
        const rawOptions = Array.isArray(data)
          ? data
          : Array.isArray(data?.data)
          ? data.data
          : null;
        if (!Array.isArray(rawOptions)) {
          throw new Error("API response does not contain a valid options array");
        }
        setOptions(rawOptions as Option[]);
      } catch (err) {
        if ((err as Error).name !== "AbortError") {
          console.error(err);
          setOptions([]);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchOptions();

    return () => {
      controller.abort();
    };
  }, [apiUrl, staticOptions, refreshTrigger]);

  // When options are loaded and value is set, update the value with the correct label
  useEffect(() => {
    if (value?.value && options.length > 0 && !loading) {
      const matchingOption = options.find((opt) => opt.value === value.value);
      if (matchingOption && matchingOption.label !== value.label) {
        // Update the value with the correct label from options
        onChange(matchingOption);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [options, loading]);

  // Resolve the value to use the label from options if available
  const resolvedValue = (() => {
    if (!value?.value || options.length === 0) return value;
    const matchingOption = options.find((opt) => opt.value === value.value);
    return matchingOption || value;
  })();

  const normalizedQuery = query.trim().toLowerCase();
  const filteredOptions = normalizedQuery
    ? options.filter((opt) =>
        opt.label?.toLowerCase().includes(normalizedQuery) ||
        opt.value?.toLowerCase().includes(normalizedQuery)
      )
    : options;
  const inputClasses = `w-full rounded-lg border ${
    error
      ? "border-red-400 focus:border-red-500 focus:ring-red-400/40"
      : "border-gray-200 hover:border-[#428B4D]/60 focus:border-[#428B4D]"
  } bg-white px-3 py-1.5 pr-10 text-sm leading-5 min-h-[2.25rem] transition-all duration-200 ease-in-out focus:outline-none focus:ring-1 focus:ring-[#428B4D]/15 placeholder:text-gray-400 disabled:bg-gray-100 disabled:text-gray-500 disabled:cursor-not-allowed disabled:hover:border-gray-200 ${className}`;

  return (
    <div className="w-full">
      {label && <label className="block mb-1 text-xs font-semibold uppercase tracking-wide text-gray-600">{label}</label>}

      <Combobox value={resolvedValue} onChange={onChange}>
        {({ open }) => {
          const ensureOpen = () => {
            if (!open) {
              buttonRef.current?.click();
            }
          };

          return (
            <div className="relative mt-1 group">
              <Combobox.Input
                className={inputClasses}
                displayValue={(opt: Option | null) => opt?.label || ""}
                onChange={(event) => setQuery(event.target.value)}
                onFocus={(e) => {
                  ensureOpen();
                  if (!error) {
                    e.currentTarget.style.borderColor = PRIMARY_COLOR;
                    e.currentTarget.style.boxShadow = `0 0 0 1px ${PRIMARY_COLOR}15`;
                  }
                }}
                onClick={ensureOpen}
                placeholder={placeholder}
                aria-invalid={Boolean(error)}
                autoComplete={autoComplete}
                onBlur={(e) => {
                  if (onBlur) onBlur();
                  if (!error) {
                    e.currentTarget.style.borderColor = "";
                    e.currentTarget.style.boxShadow = "";
                  }
                }}
                onMouseEnter={(e) => {
                  if (!error && document.activeElement !== e.currentTarget && !e.currentTarget.disabled) {
                    e.currentTarget.style.borderColor = `${PRIMARY_COLOR}99`;
                  }
                }}
                onMouseLeave={(e) => {
                  if (!error && document.activeElement !== e.currentTarget) {
                    e.currentTarget.style.borderColor = "";
                  }
                }}
              />
              <Combobox.Button
                ref={buttonRef}
                className="absolute inset-y-0 right-0 flex items-center px-2 text-gray-400 transition-all duration-200 rounded-r-lg hover:bg-[#428B4D]/5"
                style={{ color: "rgb(156, 163, 175)" }}
                onMouseEnter={(e) => {
                  e.currentTarget.style.color = PRIMARY_COLOR;
                }}
                onMouseLeave={(e) => {
                  e.currentTarget.style.color = "";
                }}
              >
                <ChevronUpDownIcon className="h-4 w-4 transition-transform duration-200 group-hover:scale-110" />
              </Combobox.Button>

              <Combobox.Options className="absolute mt-1 w-full max-h-60 overflow-auto rounded-lg bg-white border border-gray-200 text-sm focus:outline-none shadow-lg">
                {loading ? (
                  <div className="cursor-default select-none px-4 py-2 text-sm text-gray-500">
                    Loading...
                  </div>
                ) : filteredOptions.length === 0 ? (
                  <div className="cursor-default select-none px-4 py-2 text-sm text-gray-500">
                    No results found.
                  </div>
                ) : (
                  filteredOptions.map((opt) => (
                    <Combobox.Option
                      key={opt.value}
                      value={opt}
                      className={({ active }) =>
                        `relative cursor-pointer select-none py-2 pl-8 pr-3 transition-colors duration-150 ${
                          active ? "text-slate-900" : "text-gray-900 hover:bg-gray-50"
                        }`
                      }
                    >
                      {({ selected, active }) => (
                        <>
                          <span
                            className="absolute inset-0"
                            style={{
                              backgroundColor: active ? `${PRIMARY_COLOR}18` : undefined,
                            }}
                          />
                          <span className={`relative block truncate ${selected ? "font-semibold" : "font-normal"}`}>
                            {opt.label}
                          </span>
                          {selected && (
                            <span
                              className="absolute inset-y-0 left-0 flex items-center pl-2.5"
                              style={{ color: PRIMARY_COLOR }}
                            >
                              <CheckIcon className="h-4 w-4" />
                            </span>
                          )}
                        </>
                      )}
                    </Combobox.Option>
                  ))
                )}
              </Combobox.Options>
            </div>
          );
        }}
      </Combobox>
      {error && <p className="mt-1 text-sm text-red-500">{error}</p>}
    </div>
  );
};

export default SearchableSelect2;
