"use client";

import React, {
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from "react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { useDoBookmarkSearch } from "@/lib/hooks/bookmark-search";
import { useTranslation } from "@/lib/i18n/client";
import { cn } from "@/lib/utils";

import { useSearchHistory } from "@karakeep/shared-react/hooks/search-history";

import { EditListModal } from "../lists/EditListModal";
import QueryExplainerTooltip from "./QueryExplainerTooltip";
import { useSearchAutocomplete } from "./useSearchAutocomplete";

function useFocusSearchOnKeyPress(
  inputRef: React.RefObject<HTMLInputElement | null>,
  value: string,
  setValue: (value: string) => void,
  setPopoverOpen: React.Dispatch<React.SetStateAction<boolean>>,
) {
  useEffect(() => {
    function handleKeyPress(e: KeyboardEvent) {
      if (!inputRef.current) {
        return;
      }
      if ((e.metaKey || e.ctrlKey) && e.code === "KeyK") {
        e.preventDefault();
        inputRef.current.focus();
        // Move the cursor to the end of the input field, so you can continue typing
        const length = inputRef.current.value.length;
        inputRef.current.setSelectionRange(length, length);
        setPopoverOpen(true);
      }
      if (e.code === "Escape" && e.target == inputRef.current && value !== "") {
        e.preventDefault();
        inputRef.current.blur();
        setValue("");
      }
    }

    document.addEventListener("keydown", handleKeyPress);
    return () => {
      document.removeEventListener("keydown", handleKeyPress);
    };
  }, [inputRef, value, setValue, setPopoverOpen]);
}

const SearchInput = React.forwardRef<
  HTMLInputElement,
  React.HTMLAttributes<HTMLInputElement> & { loading?: boolean }
>(({ className, ...props }, ref) => {
  const { t } = useTranslation();
  const {
    debounceSearch,
    searchQuery,
    doSearch,
    parsedSearchQuery,
    isInSearchPage,
  } = useDoBookmarkSearch();
  const { addTerm, history } = useSearchHistory({
    getItem: (k: string) => localStorage.getItem(k),
    setItem: (k: string, v: string) => localStorage.setItem(k, v),
    removeItem: (k: string) => localStorage.removeItem(k),
  });

  const [value, setValue] = useState(searchQuery);
  const [isPopoverOpen, setIsPopoverOpen] = useState(false);
  const [newNestedListModalOpen, setNewNestedListModalOpen] = useState(false);

  const inputRef = useRef<HTMLInputElement>(null);
  const isHistorySelected = useRef(false);
  const isComposing = useRef(false);

  const handleValueChange = useCallback(
    (newValue: string) => {
      setValue(newValue);
      // Only trigger debounced search if not in IME composition mode
      if (!isComposing.current) {
        debounceSearch(newValue);
      }
      isHistorySelected.current = false; // Reset flag when user types
    },
    [debounceSearch],
  );

  const handleCompositionStart = useCallback(() => {
    isComposing.current = true;
  }, []);

  const handleCompositionEnd = useCallback(
    (e: React.CompositionEvent<HTMLInputElement>) => {
      isComposing.current = false;
      // Trigger search with the final composed value
      const target = e.target as HTMLInputElement;
      debounceSearch(target.value);
    },
    [debounceSearch],
  );

  const {
    suggestionGroups,
    hasSuggestions,
    isPopoverVisible,
    handleSuggestionSelect,
    handleCommandKeyDown,
  } = useSearchAutocomplete({
    value,
    onValueChange: handleValueChange,
    inputRef,
    isPopoverOpen,
    setIsPopoverOpen,
    t,
    history,
  });

  const handleHistorySelect = useCallback(
    (term: string) => {
      isHistorySelected.current = true;
      setValue(term);
      doSearch(term);
      addTerm(term);
      setIsPopoverOpen(false);
      inputRef.current?.blur();
    },
    [doSearch, addTerm],
  );

  useFocusSearchOnKeyPress(inputRef, value, setValue, setIsPopoverOpen);
  useImperativeHandle(ref, () => inputRef.current!);

  useEffect(() => {
    if (!isInSearchPage) {
      setValue("");
    }
  }, [isInSearchPage]);

  const handleFocus = useCallback(() => {
    setIsPopoverOpen(true);
  }, []);

  const handleBlur = useCallback(() => {
    // Only add to history if it wasn't a history selection
    if (value && !isHistorySelected.current) {
      addTerm(value);
    }

    // Reset the flag
    isHistorySelected.current = false;
    setIsPopoverOpen(false);
  }, [value, addTerm]);

  return (
    <div className={cn("relative flex-1", className)}>
      <EditListModal
        open={newNestedListModalOpen}
        setOpen={setNewNestedListModalOpen}
        prefill={{
          type: "smart",
          query: value,
        }}
      />
      <Link
        href="https://docs.karakeep.app/Guides/search-query-language"
        target="_blank"
        className="-translate-1/2 absolute right-1.5 top-2 z-50 stroke-foreground px-0.5"
      >
        <QueryExplainerTooltip parsedSearchQuery={parsedSearchQuery} />
      </Link>
      {parsedSearchQuery.result === "full" &&
        parsedSearchQuery.text.length == 0 && (
          <Button
            onClick={() => setNewNestedListModalOpen(true)}
            size="none"
            variant="secondary"
            className="absolute right-10 top-2 z-50 px-2 py-1 text-xs"
          >
            {t("actions.save")}
          </Button>
        )}
      <Command
        shouldFilter={false}
        className="relative rounded-md bg-transparent"
        onKeyDown={handleCommandKeyDown}
      >
        <Popover open={isPopoverVisible}>
          <PopoverTrigger asChild>
            <div className="relative">
              <CommandInput
                ref={inputRef}
                placeholder={t("common.search")}
                value={value}
                onValueChange={handleValueChange}
                onCompositionStart={handleCompositionStart}
                onCompositionEnd={handleCompositionEnd}
                onFocus={handleFocus}
                onBlur={handleBlur}
                className={cn("h-10", className)}
                {...props}
              />
            </div>
          </PopoverTrigger>
          <PopoverContent
            className="w-[--radix-popover-trigger-width] p-0"
            onOpenAutoFocus={(e) => e.preventDefault()}
            onCloseAutoFocus={(e) => e.preventDefault()}
          >
            <CommandList className="max-h-96 overflow-y-auto">
              <CommandEmpty>{t("search.no_suggestions")}</CommandEmpty>
              {hasSuggestions && <CommandItem value="-" className="hidden" />}
              {suggestionGroups.map((group) => (
                <CommandGroup key={group.id} heading={group.label}>
                  {group.items.map((item) => {
                    if (item.type === "history") {
                      return (
                        <CommandItem
                          key={item.id}
                          value={item.label}
                          onSelect={() => handleHistorySelect(item.term)}
                          onMouseDown={() => {
                            isHistorySelected.current = true;
                          }}
                          className="cursor-pointer"
                        >
                          <item.Icon className="mr-2 h-4 w-4" />
                          <span>{item.label}</span>
                        </CommandItem>
                      );
                    }

                    return (
                      <CommandItem
                        key={item.id}
                        value={item.label}
                        onSelect={() => handleSuggestionSelect(item)}
                        className="cursor-pointer"
                      >
                        <item.Icon className="mr-2 h-4 w-4" />
                        <div className="flex flex-col">
                          <span>{item.label}</span>
                          {item.description && (
                            <span className="text-xs text-muted-foreground">
                              {item.description}
                            </span>
                          )}
                        </div>
                      </CommandItem>
                    );
                  })}
                </CommandGroup>
              ))}
            </CommandList>
          </PopoverContent>
        </Popover>
      </Command>
    </div>
  );
});
SearchInput.displayName = "SearchInput";

export { SearchInput };
