import { useEffect, useRef, useState } from "react";
import { Check, Loader2, Search, X } from "lucide-react";
import type { UseFormReturn } from "react-hook-form";
import { sellerApi } from "@/lib/api/seller";
import type { ApiCatalogSuggestion } from "@/lib/api/types";
import { type ProductFormValues } from "./product.schema";
import { Field, inputClass } from "./fields";

type Props = {
  form: UseFormReturn<ProductFormValues>;
  token: string | null;
  /** Name of the catalog product the listing is linked to, if any. */
  linkedName: string | null;
  /** True while the parent is fetching the picked product and filling the form. */
  linking: boolean;
  onPick: (suggestion: ApiCatalogSuggestion) => void;
  onClear: () => void;
};

/** Wait this long after the last keystroke before asking the server. */
const DEBOUNCE_MS = 250;
const MIN_CHARS = 2;

/**
 * Product Name, with suggestions from the admin catalog.
 *
 * Most of what a seller lists is already in the catalog — the same products the
 * old /commodity-products screen made you find through four cascading dropdowns.
 * Typing the name here searches that catalog, and picking a match fills the rest
 * of the wizard from it and records which catalog product this is.
 *
 * No match is a perfectly normal outcome: the field is an ordinary text input
 * that happens to suggest, so a seller listing something new just keeps typing.
 */
export default function ProductNameField({ form, token, linkedName, linking, onPick, onClear }: Props) {
  const {
    register,
    formState: { errors },
  } = form;

  const [query, setQuery] = useState("");
  const [suggestions, setSuggestions] = useState<ApiCatalogSuggestion[]>([]);
  const [loading, setLoading] = useState(false);
  const [open, setOpen] = useState(false);
  const [highlight, setHighlight] = useState(-1);
  const boxRef = useRef<HTMLDivElement>(null);

  const { onChange: registerOnChange, ...nameField } = register("product_name");

  useEffect(() => {
    const term = query.trim();
    if (!token || term.length < MIN_CHARS) {
      setSuggestions([]);
      setLoading(false);
      return;
    }

    const controller = new AbortController();
    setLoading(true);
    const timer = setTimeout(() => {
      sellerApi
        .catalogSuggestions(token, term, controller.signal)
        .then((res) => {
          setSuggestions(res.data ?? []);
          setHighlight(-1);
        })
        .catch(() => {
          // An aborted request is the normal case here — the seller typed
          // another character. Either way there is nothing to show.
          setSuggestions([]);
        })
        .finally(() => setLoading(false));
    }, DEBOUNCE_MS);

    return () => {
      clearTimeout(timer);
      controller.abort();
    };
  }, [query, token]);

  // A click anywhere else closes the list, the way a native <select> would.
  useEffect(() => {
    if (!open) return;
    const onDocumentClick = (event: MouseEvent) => {
      if (!boxRef.current?.contains(event.target as Node)) setOpen(false);
    };
    document.addEventListener("mousedown", onDocumentClick);
    return () => document.removeEventListener("mousedown", onDocumentClick);
  }, [open]);

  const pick = (suggestion: ApiCatalogSuggestion) => {
    setOpen(false);
    setSuggestions([]);
    setQuery("");
    onPick(suggestion);
  };

  const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
    if (!open || suggestions.length === 0) return;

    if (event.key === "ArrowDown") {
      event.preventDefault();
      setHighlight((prev) => (prev + 1) % suggestions.length);
    } else if (event.key === "ArrowUp") {
      event.preventDefault();
      setHighlight((prev) => (prev <= 0 ? suggestions.length - 1 : prev - 1));
    } else if (event.key === "Enter" && highlight >= 0) {
      // Without this the keypress submits the wizard instead of choosing.
      event.preventDefault();
      pick(suggestions[highlight]);
    } else if (event.key === "Escape") {
      setOpen(false);
    }
  };

  const showList = open && (loading || suggestions.length > 0 || query.trim().length >= MIN_CHARS);

  return (
    <Field
      label="Product Name"
      required
      error={errors.product_name?.message}
      className="md:col-span-2"
    >
      <div ref={boxRef} className="relative">
        <input
          {...nameField}
          onChange={(event) => {
            registerOnChange(event);
            setQuery(event.target.value);
            setOpen(true);
          }}
          onFocus={() => {
            if (suggestions.length > 0) setOpen(true);
          }}
          onKeyDown={onKeyDown}
          className={`${inputClass} pr-9`}
          placeholder="Start typing — we'll suggest products from our catalog"
          autoComplete="off"
          role="combobox"
          aria-expanded={showList}
          aria-controls="catalog-product-suggestions"
          aria-autocomplete="list"
        />
        <span className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400">
          {loading || linking ? (
            <Loader2 className="h-4 w-4 animate-spin" />
          ) : (
            <Search className="h-4 w-4" />
          )}
        </span>

        {showList ? (
          <ul
            id="catalog-product-suggestions"
            role="listbox"
            className="absolute z-20 mt-1 max-h-72 w-full overflow-y-auto rounded-lg border border-gray-200 bg-white py-1 shadow-lg"
          >
            {suggestions.length === 0 ? (
              <li className="px-3 py-2 text-xs text-gray-500">
                {loading
                  ? "Searching our catalog…"
                  : "No match in our catalog — carry on and fill in the details yourself."}
              </li>
            ) : (
              suggestions.map((suggestion, index) => (
                <li key={suggestion.id} role="option" aria-selected={index === highlight}>
                  <button
                    type="button"
                    // mousedown, not click: the input blurs first otherwise and
                    // the list is gone before the click lands.
                    onMouseDown={(event) => {
                      event.preventDefault();
                      pick(suggestion);
                    }}
                    onMouseEnter={() => setHighlight(index)}
                    className={`flex w-full items-center gap-3 px-3 py-2 text-left ${
                      index === highlight ? "bg-rose-50" : "bg-white"
                    }`}
                  >
                    {suggestion.thumbnail ? (
                      // eslint-disable-next-line @next/next/no-img-element
                      <img
                        src={suggestion.thumbnail}
                        alt=""
                        className="h-8 w-8 shrink-0 rounded object-cover"
                      />
                    ) : (
                      <span className="h-8 w-8 shrink-0 rounded bg-gray-100" />
                    )}
                    <span className="min-w-0">
                      <span className="block truncate text-sm font-medium text-gray-900">
                        {suggestion.name}
                      </span>
                      <span className="block truncate text-xs text-gray-500">
                        {[suggestion.category, suggestion.sub_category, suggestion.unit]
                          .filter(Boolean)
                          .join(" · ") || "Catalog product"}
                      </span>
                    </span>
                  </button>
                </li>
              ))
            )}
          </ul>
        ) : null}
      </div>

      {linkedName ? (
        <div className="mt-2 flex flex-wrap items-center gap-2 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-800">
          <Check className="h-3.5 w-3.5 shrink-0" />
          <span className="min-w-0">
            Linked to <span className="font-semibold">{linkedName}</span> in our catalog — the rest of
            the wizard has been filled in from it. Change anything that differs for your offer.
          </span>
          <button
            type="button"
            onClick={onClear}
            className="ml-auto inline-flex items-center gap-1 rounded-md border border-emerald-300 px-2 py-1 font-medium hover:bg-emerald-100"
          >
            <X className="h-3 w-3" /> Unlink
          </button>
        </div>
      ) : (
        <p className="mt-1 text-xs text-gray-500">
          Pick a suggestion to fill the form automatically, or type your own product name.
        </p>
      )}
    </Field>
  );
}
