import { useState, useCallback, useEffect, useMemo, useRef } from "react";
import { ActionIcon, TextInput, ScrollArea, Loader } from "@mantine/core";
import { useDebouncedValue } from "@mantine/hooks";
import { IconSearch, IconFileDescription } from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
import { useGetSpacesQuery } from "@/features/space/queries/space-query";
import { useSearchSuggestionsQuery } from "@/features/search/queries/search-query";
import { ISpace } from "@/features/space/types/space.types";
import { IPage } from "@/features/page/types/page.types";
import { DestinationSelection } from "./destination-picker.types";
import { SpaceRow } from "./space-row";
import classes from "./destination-picker.module.css";

type DestinationPickerProps = {
  onSelectionChange: (selection: DestinationSelection | null) => void;
  excludePageId?: string;
  pageLimit?: number;
  initialSpaceId?: string;
  searchSpacesOnly?: boolean;
};

export function DestinationPicker({
  onSelectionChange,
  excludePageId,
  pageLimit = 15,
  initialSpaceId,
  searchSpacesOnly,
}: DestinationPickerProps) {
  const { t } = useTranslation();
  const [searchQuery, setSearchQuery] = useState("");
  const [selection, setSelection] = useState<DestinationSelection | null>(null);
  const [debouncedQuery] = useDebouncedValue(searchQuery, 300);
  const viewportRef = useRef<HTMLDivElement>(null);

  const { data: spacesData, isLoading: spacesLoading } = useGetSpacesQuery({
    limit: 100,
  });

  const searchEnabled =
    !searchSpacesOnly && debouncedQuery && debouncedQuery.length >= 2;

  const { data: searchData, isLoading: searchLoading } =
    useSearchSuggestionsQuery({
      query: searchEnabled ? debouncedQuery : "",
      includePages: true,
      limit: 20,
    });

  const isSearching = !!searchEnabled;

  const filteredSpaces = useMemo(() => {
    const items = spacesData?.items ?? [];
    if (!searchSpacesOnly || !debouncedQuery) return items;
    const fold = (s: string) =>
      s
        .normalize("NFD")
        .replace(/[̀-ͯ]/g, "")
        .toLocaleLowerCase();
    const term = fold(debouncedQuery);
    return items.filter((s) => fold(s.name).includes(term));
  }, [spacesData, searchSpacesOnly, debouncedQuery]);

  const selectedId =
    selection?.type === "space" ? selection.spaceId : selection?.pageId ?? null;

  const updateSelection = useCallback(
    (next: DestinationSelection | null) => {
      setSelection(next);
      onSelectionChange(next);
    },
    [onSelectionChange],
  );

  const handleSearchResultClick = (page: Partial<IPage>) => {
    if (!page.space || !page.id) return;

    updateSelection({
      type: "page",
      spaceId: page.space.id,
      pageId: page.id,
      page,
      space: page.space,
    });
    setSearchQuery("");
  };

  const handleSelectSpace = useCallback(
    (space: ISpace) => {
      updateSelection({ type: "space", spaceId: space.id, space });
    },
    [updateSelection],
  );

  const handleSelectPage = useCallback(
    (page: Partial<IPage>, space: ISpace) => {
      if (!page.id) return;
      updateSelection({
        type: "page",
        spaceId: page.spaceId ?? space.id,
        pageId: page.id,
        page,
        space,
      });
    },
    [updateSelection],
  );

  // Pre-select space when initialSpaceId is set and spaces have loaded.
  // Only runs once: skip if user has already made a selection.
  useEffect(() => {
    if (!initialSpaceId || selection) return;
    const match = spacesData?.items?.find((s) => s.id === initialSpaceId);
    if (match) {
      updateSelection({ type: "space", spaceId: match.id, space: match });
      requestAnimationFrame(() => {
        const el = viewportRef.current?.querySelector<HTMLElement>(
          `[data-space-id="${match.id}"]`,
        );
        el?.scrollIntoView({ block: "nearest" });
      });
    }
  }, [initialSpaceId, selection, spacesData, updateSelection]);

  return (
    <>
      <TextInput
        leftSection={<IconSearch size={16} />}
        placeholder={
          searchSpacesOnly
            ? t("Search spaces...")
            : t("Search pages and spaces...")
        }
        aria-label={
          searchSpacesOnly
            ? t("Search spaces...")
            : t("Search pages and spaces...")
        }
        variant="filled"
        value={searchQuery}
        onChange={(e) => setSearchQuery(e.currentTarget.value)}
        className={classes.searchInput}
      />

      <ScrollArea
        h="50vh"
        offsetScrollbars
        className={classes.scrollArea}
        viewportRef={viewportRef}
      >
        {isSearching ? (
          searchLoading ? (
            <div className={classes.emptyState}>
              <Loader size="xs" />
            </div>
          ) : searchData?.pages && searchData.pages.length > 0 ? (
            searchData.pages.map(
              (page) =>
                page && (
                  <div
                    key={page.id}
                    className={classes.searchResult}
                    role="button"
                    tabIndex={0}
                    onClick={() => handleSearchResultClick(page)}
                    onKeyDown={(e) => {
                      if (e.key === "Enter" || e.key === " ") {
                        e.preventDefault();
                        handleSearchResultClick(page);
                      }
                    }}
                  >
                    <div className={classes.iconWrapper}>
                      {page.icon ? (
                        page.icon
                      ) : (
                        <ActionIcon
                          component="div"
                          variant="transparent"
                          c="gray"
                          size={22}
                        >
                          <IconFileDescription size={18} />
                        </ActionIcon>
                      )}
                    </div>
                    <div className={classes.pageTitle}>
                      {page.title || t("Untitled")}
                    </div>
                    {page.space && (
                      <div className={classes.spaceName}>
                        {page.space.name}
                      </div>
                    )}
                  </div>
                ),
            )
          ) : (
            <div className={classes.emptyState}>{t("No results found")}</div>
          )
        ) : spacesLoading ? (
          <div className={classes.emptyState}>
            <Loader size="xs" />
          </div>
        ) : filteredSpaces.length === 0 ? (
          <div className={classes.emptyState}>
            {searchSpacesOnly && debouncedQuery
              ? t("No spaces found")
              : t("No results found")}
          </div>
        ) : (
          filteredSpaces.map((space) => (
            <SpaceRow
              key={space.id}
              space={space}
              limit={pageLimit}
              selectedId={selectedId}
              excludePageId={excludePageId}
              onSelectSpace={handleSelectSpace}
              onSelectPage={handleSelectPage}
            />
          ))
        )}
      </ScrollArea>
    </>
  );
}
