"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 | number;
  ticker?: string;
  isin?: string;
}

interface SearchableSelect2Props {
  label?: string;
  apiUrl?: string;
  /** Merged into the JSON body of every options fetch (e.g. { a_class: 1430 }). */
  apiPostBody?: Record<string, unknown>;
  staticOptions?: Option[];
  value?: Option | null;
  onChange: (value: Option | null) => void;
  placeholder?: string;
  error?: string;
  className?: string;
  autoComplete?: string;
  onBlur?: () => void;
  refreshTrigger?: unknown;
  serverSideSearch?: boolean;
  isDisabled?: boolean;
}

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

  useEffect(() => {
    if (staticOptions) {
      setOptions(staticOptions);
    }
  }, [staticOptions]);

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

    let cancelled = false;
    const controller = new AbortController();
    const delay = serverSideSearch && query ? 300 : 50;

    const timer = setTimeout(async () => {
      if (cancelled) return;
      setLoading(true);
      try {
        const baseBody = apiPostBody ? { ...apiPostBody } : {};
        const response = await fetch(apiUrl, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(
            serverSideSearch
              ? { ...baseBody, search: query.trim(), limit: 100 }
              : baseBody
          ),
          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("Invalid options array");
        if (!cancelled) setOptions(rawOptions as Option[]);
      } catch (err) {
        if ((err as Error).name !== "AbortError") {
          if (!cancelled) setOptions([]);
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    }, delay);

    return () => {
      cancelled = true;
      clearTimeout(timer);
      controller.abort();
    };
  }, [apiUrl, apiPostBodyKey, staticOptions, refreshTrigger, serverSideSearch, query]);

  useEffect(() => {
    if (value?.value && options.length > 0 && !loading) {
      const matchingOption = options.find((opt) => String(opt.value) === String(value.value));
      if (matchingOption && matchingOption.label !== value.label) {
        onChange(matchingOption);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [options, loading]);

  const resolvedValue = (() => {
    if (!value?.value || options.length === 0) return value;
    const matchingOption = options.find((opt) => String(opt.value) === String(value.value));
    return matchingOption || value;
  })();

  const normalizedQuery = query.trim().toLowerCase();
  const filteredOptions = serverSideSearch
    ? options
    : normalizedQuery
    ? options.filter((opt) =>
        opt.label?.toLowerCase().includes(normalizedQuery) ||
        String(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 (isDisabled) return;   // ✅ ADD THIS
            if (!open) buttonRef.current?.click();
          };

          return (
            <div className="relative mt-1 group">
              <Combobox.Input
                className={inputClasses}
                disabled={isDisabled}
                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"
                disabled={isDisabled}
                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 z-50">
                {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;