"use client";

import { useState, useRef, useEffect, useLayoutEffect, useCallback } from "react";
import { createPortal } from "react-dom";
import { ChevronDown, Search, X } from "lucide-react";
import type { AccountGroup } from "@/app/(portal)/po/new/new-po-form";

interface Props {
  name: string;
  value: string;
  onChange: (value: string) => void;
  groups: AccountGroup[];
  placeholder?: string;
  required?: boolean;
  /** "default" for the main PO field, "compact" for the per-line-item table cell */
  size?: "default" | "compact";
}

export function SearchableSelect({
  name,
  value,
  onChange,
  groups,
  placeholder = "Select accounting code…",
  required,
  size = "default",
}: Props) {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState("");
  const containerRef = useRef<HTMLDivElement>(null);
  const searchRef = useRef<HTMLInputElement>(null);
  const [portalStyle, setPortalStyle] = useState<React.CSSProperties>({});
  const [mounted, setMounted] = useState(false);

  useEffect(() => { setMounted(true); }, []);

  // Recalculate portal position on open, scroll, and resize so the panel tracks
  // the trigger even when the page (or any ancestor) is scrolled.
  const updatePortalPos = useCallback(() => {
    if (!containerRef.current) return;
    const rect = containerRef.current.getBoundingClientRect();
    const PANEL_WIDTH = 420;
    const left = Math.max(8, rect.right - PANEL_WIDTH);
    setPortalStyle({
      position: "fixed",
      top: rect.bottom + 4,
      left,
      width: PANEL_WIDTH,
      zIndex: 9999,
    });
  }, []);

  useLayoutEffect(() => {
    if (!open) return;
    updatePortalPos();
  }, [open, updatePortalPos]);

  useEffect(() => {
    if (!open) return;
    // capture:true catches scroll on any ancestor, not just window
    window.addEventListener("scroll", updatePortalPos, true);
    window.addEventListener("resize", updatePortalPos);
    return () => {
      window.removeEventListener("scroll", updatePortalPos, true);
      window.removeEventListener("resize", updatePortalPos);
    };
  }, [open, updatePortalPos]);

  // Close on outside click / Escape
  useEffect(() => {
    if (!open) return;
    function handleKey(e: KeyboardEvent) {
      if (e.key === "Escape") { setOpen(false); setQuery(""); }
    }
    function handleClick(e: MouseEvent) {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setOpen(false);
        setQuery("");
      }
    }
    document.addEventListener("keydown", handleKey);
    document.addEventListener("mousedown", handleClick);
    return () => {
      document.removeEventListener("keydown", handleKey);
      document.removeEventListener("mousedown", handleClick);
    };
  }, [open]);

  // Auto-focus search input when opened
  useEffect(() => {
    if (open) searchRef.current?.focus();
  }, [open]);

  const selectedItem = groups.flatMap((g) => g.items).find((i) => i.id === value);
  const selectedLabel = selectedItem ? `${selectedItem.code} — ${selectedItem.name}` : "";

  const q = query.trim().toLowerCase();
  const filtered = q
    ? groups
        .map((g) => ({
          ...g,
          items: g.items.filter(
            (i) => i.code.toLowerCase().includes(q) || i.name.toLowerCase().includes(q)
          ),
        }))
        .filter((g) => g.items.length > 0)
    : groups;

  const handleSelect = useCallback((id: string) => {
    onChange(id);
    setOpen(false);
    setQuery("");
  }, [onChange]);

  const handleClear = useCallback((e: React.MouseEvent) => {
    e.stopPropagation();
    onChange("");
  }, [onChange]);

  const isCompact = size === "compact";

  const dropdownPanel = (
    <div
      style={isCompact ? portalStyle : undefined}
      className={`rounded-lg border border-neutral-200 bg-white shadow-xl
        ${isCompact ? "" : "absolute z-50 left-0 right-0 mt-1"}`}
    >
      {/* Search input */}
      <div className="flex items-center gap-2 p-2 border-b border-neutral-100">
        <Search className="h-4 w-4 text-neutral-400 shrink-0" />
        <input
          ref={searchRef}
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Type code or name…"
          className="flex-1 text-sm outline-none placeholder:text-neutral-400"
        />
        {query && (
          <button type="button" onClick={() => setQuery("")} className="text-neutral-300 hover:text-neutral-500">
            <X className="h-3.5 w-3.5" />
          </button>
        )}
      </div>

      {/* Options list */}
      <div className="max-h-72 overflow-y-auto overscroll-contain [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-neutral-300">
        {filtered.length === 0 ? (
          <p className="px-3 py-5 text-sm text-center text-neutral-400">No codes match &ldquo;{query}&rdquo;</p>
        ) : (
          filtered.map((group) => {
            // Strip top-level breadcrumb — show only the sub-category part
            const groupLabel = group.group.includes("›")
              ? group.group.split("›").pop()!.trim()
              : group.group;
            return (
              <div key={group.group}>
                <div className="sticky top-0 px-3 py-1 text-xs font-semibold text-neutral-500 bg-neutral-50 border-b border-neutral-100 truncate">
                  {groupLabel}
                </div>
                {group.items.map((item) => (
                  <button
                    key={item.id}
                    type="button"
                    onMouseDown={(e) => { e.preventDefault(); handleSelect(item.id); }}
                    className={`w-full text-left flex items-baseline gap-2.5 px-3 py-2 text-sm hover:bg-primary-50 transition-colors
                      ${value === item.id ? "bg-primary-50 text-primary-700 font-medium" : "text-neutral-800"}`}
                  >
                    <span className="font-mono text-xs text-neutral-400 shrink-0 w-14">{item.code}</span>
                    <span className="flex-1 leading-snug">{item.name}</span>
                  </button>
                ))}
              </div>
            );
          })
        )}
      </div>
    </div>
  );

  return (
    <div ref={containerRef} className="relative w-full">
      <input type="hidden" name={name} value={value} />
      {required && !value && (
        <input tabIndex={-1} required value={value} onChange={() => {}}
          className="absolute opacity-0 w-0 h-0 pointer-events-none" aria-hidden />
      )}

      {/* Trigger button — same appearance for both sizes */}
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        className={`w-full flex items-center justify-between gap-2 rounded-lg border
          ${open ? "border-primary-500 ring-2 ring-primary-500/20" : "border-neutral-300"}
          bg-white text-left transition-colors
          focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20
          ${isCompact ? "px-2 py-1.5 text-xs" : "px-3 py-2.5 text-sm"}`}
      >
        <span className={`truncate flex-1 min-w-0 ${selectedLabel ? "text-neutral-900" : "text-neutral-400"}`}>
          {selectedLabel || placeholder}
        </span>
        <span className="flex items-center gap-1 shrink-0">
          {value && (
            <span role="button" tabIndex={0} onClick={handleClear}
              onKeyDown={(e) => e.key === "Enter" && handleClear(e as unknown as React.MouseEvent)}
              className="text-neutral-300 hover:text-neutral-500 transition-colors">
              <X className={isCompact ? "h-3 w-3" : "h-4 w-4"} />
            </span>
          )}
          <ChevronDown className={`text-neutral-400 transition-transform ${open ? "rotate-180" : ""} ${isCompact ? "h-3 w-3" : "h-4 w-4"}`} />
        </span>
      </button>

      {/* Dropdown: compact uses a portal (fixed) to escape overflow-x-auto containers */}
      {open && (
        isCompact && mounted
          ? createPortal(dropdownPanel, document.body)
          : dropdownPanel
      )}
    </div>
  );
}
