import {
  useCallback,
  useEffect,
  useId,
  useMemo,
  useRef,
  useState,
  type FormEvent,
  type KeyboardEvent,
} from "react";
import { Link, useNavigate } from "@tanstack/react-router";
import { ArrowRight, FlaskConical, Loader2, Search } from "lucide-react";
import { useProductSearch } from "@/hooks/useWooCommerce";
import { products as mockProducts, type Product } from "@/data/mockProducts";
import { useT } from "@/lib/i18n";

/**
 * The site's search field with live results.
 *
 * Typing shows a dropdown under the field with an image, title and price per
 * product; clicking (or Enter on the highlighted row) opens the product page.
 * Enter without a highlighted row runs the full search on /shop.
 *
 * Two variants share this component: the field in the header and the one in the
 * mobile drawer, so both behave and look the same.
 */
interface SearchBoxProps {
  variant?: "header" | "drawer";
  /** Called after navigating, so the drawer can close itself. */
  onNavigate?: () => void;
}

const MIN_CHARS = 2;
const DEBOUNCE_MS = 220;
const MAX_RESULTS = 6;

function highlightMatch(name: string, query: string) {
  if (query === "") return name;

  const index = name.toLowerCase().indexOf(query.toLowerCase());

  if (index === -1) return name;

  return (
    <>
      {name.slice(0, index)}
      <span className="text-brand-gold-hi">{name.slice(index, index + query.length)}</span>
      {name.slice(index + query.length)}
    </>
  );
}

export default function SearchBox({ variant = "header", onNavigate }: SearchBoxProps) {
  const t = useT();
  const navigate = useNavigate();
  const rawId = useId();
  const listId = `${variant}-search-${rawId.replace(/[^a-zA-Z0-9]/g, "")}`;
  const rootRef = useRef<HTMLDivElement>(null);

  const [query, setQuery] = useState("");
  const [debounced, setDebounced] = useState("");
  const [open, setOpen] = useState(false);
  const [activeIndex, setActiveIndex] = useState(-1);

  // One request per pause in typing instead of one per keystroke.
  useEffect(() => {
    const trimmed = query.trim();

    if (trimmed.length < MIN_CHARS) {
      setDebounced("");

      return;
    }

    const timer = setTimeout(() => setDebounced(trimmed), DEBOUNCE_MS);

    return () => clearTimeout(timer);
  }, [query]);

  const search = useProductSearch(debounced, MAX_RESULTS);
  const pending = search.isFetching || debounced !== query.trim();

  const results: Product[] = useMemo(() => {
    if (debounced.length < MIN_CHARS) return [];
    if (search.data) return search.data.products.slice(0, MAX_RESULTS);

    // The shop is unreachable: fall back to the local catalogue so the field
    // still leads somewhere instead of showing nothing.
    if (search.isError) {
      const needle = debounced.toLowerCase();

      return mockProducts
        .filter((product) => product.name.toLowerCase().includes(needle))
        .slice(0, MAX_RESULTS);
    }

    return [];
  }, [debounced, search.data, search.isError]);

  const visible = open && query.trim().length >= MIN_CHARS;

  useEffect(() => setActiveIndex(-1), [debounced]);

  useEffect(() => {
    if (!visible) return;

    const onPointerDown = (event: MouseEvent) => {
      if (rootRef.current && !rootRef.current.contains(event.target as Node)) setOpen(false);
    };

    document.addEventListener("mousedown", onPointerDown);

    return () => document.removeEventListener("mousedown", onPointerDown);
  }, [visible]);

  const reset = useCallback(() => {
    setQuery("");
    setDebounced("");
    setOpen(false);
    setActiveIndex(-1);
    onNavigate?.();
  }, [onNavigate]);

  const openProduct = useCallback(
    (slug: string) => {
      reset();
      void navigate({ to: "/product/$slug", params: { slug } });
    },
    [navigate, reset],
  );

  const submit = (event?: FormEvent) => {
    event?.preventDefault();

    const highlighted = activeIndex >= 0 ? results[activeIndex] : undefined;

    if (highlighted) {
      openProduct(highlighted.slug);

      return;
    }

    const term = query.trim();

    if (term === "") return;

    reset();
    void navigate({ to: "/shop", search: { zoeken: term } });
  };

  const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
    if (event.key === "Escape") {
      setOpen(false);
      setActiveIndex(-1);

      return;
    }

    if (!visible || results.length === 0) return;

    if (event.key === "ArrowDown") {
      event.preventDefault();
      setActiveIndex((index) => (index + 1) % results.length);
    }

    if (event.key === "ArrowUp") {
      event.preventDefault();
      setActiveIndex((index) => (index <= 0 ? results.length - 1 : index - 1));
    }
  };

  const inputClass =
    variant === "header"
      ? "w-full pl-11 pr-20 py-2 rounded-full bg-shell-foreground/5 text-shell-foreground placeholder:text-shell-foreground/30 border border-shell-border text-sm focus:outline-none focus:border-brand-gold/50 transition-all"
      : "w-full pl-11 pr-11 py-2.5 rounded-full bg-shell-foreground/5 text-shell-foreground placeholder:text-shell-foreground/30 border border-shell-border text-sm outline-none focus:border-brand-gold/50 transition-all";

  return (
    <div ref={rootRef} className="relative w-full">
      <form onSubmit={submit} role="search">
        <div className="relative w-full">
          <Search
            className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-brand-gold"
            aria-hidden="true"
          />
          <input
            type="text"
            value={query}
            onChange={(event) => {
              setQuery(event.target.value);
              setOpen(true);
            }}
            onFocus={() => setOpen(true)}
            onKeyDown={onKeyDown}
            placeholder={t("Zoek peptides, BPC-157...", "Search peptides, BPC-157...")}
            maxLength={100}
            role="combobox"
            aria-expanded={visible}
            aria-controls={listId}
            aria-autocomplete="list"
            aria-activedescendant={
              visible && activeIndex >= 0 && results[activeIndex]
                ? `${listId}-option-${activeIndex}`
                : undefined
            }
            className={inputClass}
          />
          {variant === "header" ? (
            <button
              type="submit"
              className="absolute right-1 top-1/2 -translate-y-1/2 bg-gradient-to-r from-brand-gold-lo to-brand-gold text-brand-gold-contrast text-[10px] font-bold uppercase tracking-wider px-4 py-1.5 rounded-full hover:brightness-110 transition-all"
            >
              {t("Zoek", "Search")}
            </button>
          ) : (
            pending && (
              <Loader2
                className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 animate-spin text-brand-gold"
                aria-hidden="true"
              />
            )
          )}
        </div>
      </form>

      {visible && (
        <div className="absolute top-full left-0 right-0 z-50 mt-1.5 overflow-hidden rounded-2xl border border-border/50 bg-card text-card-foreground shadow-xl animate-in fade-in slide-in-from-top-2 duration-200">
          <div className="flex items-center justify-between gap-2 border-b border-border/50 px-4 py-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
            <span>{t("Producten", "Products")}</span>
            {pending && results.length > 0 && (
              <Loader2 className="w-3.5 h-3.5 animate-spin text-brand-gold" aria-hidden="true" />
            )}
          </div>

          {results.length > 0 ? (
            <ul
              id={listId}
              role="listbox"
              aria-label={t("Zoekresultaten", "Search results")}
              className="max-h-[22rem] overflow-y-auto py-1.5"
            >
              {results.map((product, index) => (
                <li
                  key={product.id}
                  id={`${listId}-option-${index}`}
                  role="option"
                  aria-selected={index === activeIndex}
                >
                  <Link
                    to="/product/$slug"
                    params={{ slug: product.slug }}
                    onClick={reset}
                    onMouseEnter={() => setActiveIndex(index)}
                    className={`flex items-center gap-3 px-3.5 py-2.5 transition-colors ${
                      index === activeIndex ? "bg-muted/70" : "hover:bg-muted/50"
                    }`}
                  >
                    <span className="flex h-14 w-14 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-border/60 bg-surface">
                      {product.image ? (
                        <img
                          src={product.image}
                          alt={product.name}
                          width={56}
                          height={56}
                          loading="lazy"
                          decoding="async"
                          className="h-full w-full object-contain p-1"
                        />
                      ) : (
                        <FlaskConical
                          className="h-5 w-5 text-muted-foreground"
                          aria-hidden="true"
                        />
                      )}
                    </span>

                    <span className="min-w-0 flex-1">
                      <span className="block truncate text-sm font-medium">
                        {highlightMatch(product.name, debounced)}
                      </span>
                      {product.category && (
                        <span className="mt-0.5 block truncate text-[11px] text-muted-foreground">
                          {product.category}
                        </span>
                      )}
                    </span>

                    <span className="shrink-0 text-right">
                      {product.salePrice ? (
                        <>
                          <span className="block text-[11px] text-muted-foreground line-through">
                            €{product.price.toFixed(2)}
                          </span>
                          <span className="block text-sm font-bold text-primary">
                            €{product.salePrice.toFixed(2)}
                          </span>
                        </>
                      ) : (
                        <span className="block text-sm font-bold text-primary">
                          €{product.price.toFixed(2)}
                        </span>
                      )}
                      {product.inStock === false && (
                        <span className="block text-[10px] text-muted-foreground">
                          {t("Uitverkocht", "Sold out")}
                        </span>
                      )}
                    </span>
                  </Link>
                </li>
              ))}
            </ul>
          ) : pending ? (
            <div className="space-y-3 p-4">
              {[1, 2, 3].map((row) => (
                <div key={row} className="flex animate-pulse items-center gap-3">
                  <div className="h-14 w-14 shrink-0 rounded-xl bg-muted" />
                  <div className="flex-1 space-y-2">
                    <div className="h-3 w-3/4 rounded-full bg-muted" />
                    <div className="h-2.5 w-1/3 rounded-full bg-muted" />
                  </div>
                </div>
              ))}
            </div>
          ) : (
            <div className="p-6 text-center">
              <Search
                className="mx-auto mb-2 h-8 w-8 text-muted-foreground/40"
                aria-hidden="true"
              />
              <p className="text-sm font-medium text-muted-foreground">
                {t("Geen resultaten voor", "No results for")} &ldquo;{debounced}&rdquo;
              </p>
            </div>
          )}

          <Link
            to="/shop"
            search={{ zoeken: query.trim() }}
            onClick={reset}
            className="flex items-center justify-center gap-2 border-t border-border/50 px-4 py-3 text-sm font-semibold text-primary transition-colors hover:bg-primary/5"
          >
            {t("Alle resultaten bekijken", "View all results")}{" "}
            <ArrowRight className="h-4 w-4" aria-hidden="true" />
          </Link>
        </div>
      )}
    </div>
  );
}
