"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Search } from "lucide-react";
import { TreePickerSurface } from "@/components/sidebar/tree-shell-surface";
import type { TreeShellPickerCommand } from "@/components/sidebar/tree-shell-host";
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type { SidebarInitialData } from "@/components/sidebar/types";
import { getMnoteRuntimeConfig } from "@/lib/runtime-config";
import { buildPageTreeProjectionItems, buildPickerTreeItems } from "@/lib/tree-projection";
import { useDocumentSearch } from "@/hooks/use-document-search";
import type { DocumentSearchFilters, DocumentSearchResult } from "@/types/search";

export type MoveEmbedMode = "move" | "embed";
const PICKER_ROOT_ITEM_KEY = "__root__";

const DEFAULT_FILTERS: DocumentSearchFilters = {
  titleOnly: true,
  exact: false,
  onlyCurrentPage: false,
  includeOcr: false,
  timeRange: "any",
  timeField: "updated",
};

type PickerItem =
  | { kind: "root"; id: null; title: string; subtitle?: string }
  | { kind: "doc"; id: string; title: string; subtitle?: string; depth?: number; raw?: DocumentSearchResult };

async function fetchSidebarData(workspaceId: string): Promise<SidebarInitialData> {
  const response = await fetch(`/api/sidebar?workspaceId=${encodeURIComponent(workspaceId)}`, {
    method: "GET",
    credentials: "include",
  });

  if (!response.ok) {
    const payload = await response.json().catch(() => ({}));
    const message = payload?.error ?? "获取页面列表失败";
    throw new Error(message);
  }

  return response.json();
}

interface MoveEmbedPickerDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  workspaceId: string | null;
  defaultMode?: MoveEmbedMode;
  modes?: MoveEmbedMode[];
  allowRoot?: boolean;
  excludeIds?: string[];
  onPick: (mode: MoveEmbedMode, targetId: string | null) => void | Promise<void>;
}

export function MoveEmbedPickerDialog({
  open,
  onOpenChange,
  workspaceId,
  defaultMode = "move",
  modes = ["move", "embed"],
  allowRoot = true,
  excludeIds = [],
  onPick,
}: MoveEmbedPickerDialogProps) {
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-h-[90vh] w-full max-w-md overflow-hidden border-none bg-white p-0 shadow-xl">
        <DialogTitle className="sr-only">选择目标页面</DialogTitle>
        {open ? (
          <MoveEmbedPickerDialogBody
            onOpenChange={onOpenChange}
            workspaceId={workspaceId}
            defaultMode={defaultMode}
            modes={modes}
            allowRoot={allowRoot}
            excludeIds={excludeIds}
            onPick={onPick}
          />
        ) : null}
      </DialogContent>
    </Dialog>
  );
}

interface MoveEmbedPickerDialogBodyProps {
  onOpenChange: (open: boolean) => void;
  workspaceId: string | null;
  defaultMode: MoveEmbedMode;
  modes: MoveEmbedMode[];
  allowRoot: boolean;
  excludeIds: string[];
  onPick: (mode: MoveEmbedMode, targetId: string | null) => void | Promise<void>;
}

function MoveEmbedPickerDialogBody({
  onOpenChange,
  workspaceId,
  defaultMode,
  modes,
  allowRoot,
  excludeIds,
  onPick,
}: MoveEmbedPickerDialogBodyProps) {
  const [mode, setMode] = useState<MoveEmbedMode>(defaultMode);
  const [query, setQuery] = useState("");
  const [highlighted, setHighlighted] = useState(0);
  const [pickerCommand, setPickerCommand] = useState<TreeShellPickerCommand | null>(null);
  const searchInputRef = useRef<HTMLInputElement | null>(null);
  const keyboardHighlightPendingRef = useRef(false);
  const treeRendererFamily = getMnoteRuntimeConfig().treeRendererFamily ?? "rust_family";
  const canDelegatePickerKeyboardToShell = treeRendererFamily === "rust_family" && Boolean(workspaceId);

  const handleModeChange = useCallback((value: string) => {
    setMode(value as MoveEmbedMode);
    setQuery("");
    setHighlighted(0);
  }, []);

  const handleQueryChange = useCallback((value: string) => {
    setQuery(value);
    setHighlighted(0);
  }, []);

  const queuePickerCommand = useCallback((kind: TreeShellPickerCommand["kind"]) => {
    setPickerCommand((prev) => ({
      kind,
      seq: (prev?.seq ?? 0) + 1,
    }));
  }, []);

  const payload = useMemo(() => {
    if (!workspaceId) return null;
    return {
      workspaceId,
      query,
      filters: DEFAULT_FILTERS,
      limit: 30,
    };
  }, [query, workspaceId]);

  const trimmed = query.trim();
  const isEmptyQuery = trimmed.length === 0;

  const sidebarQuery = useQuery({
    queryKey: ["move-embed-picker-sidebar", workspaceId],
    queryFn: () => {
      if (!workspaceId) {
        throw new Error("缺少 workspaceId");
      }
      return fetchSidebarData(workspaceId);
    },
    enabled: Boolean(workspaceId) && isEmptyQuery,
    staleTime: 30_000,
    gcTime: 60_000,
  });

  const { data, isLoading, error } = useDocumentSearch(payload, Boolean(payload) && !isEmptyQuery);

  const items = useMemo<PickerItem[]>(() => {
    const excluded = new Set(excludeIds);

    const result: PickerItem[] = [];

    if (isEmptyQuery) {
      if (allowRoot && mode === "move") {
        result.push({ kind: "root", id: null, title: "根目录", subtitle: "移动到工作空间根目录" });
      }

      const tree = sidebarQuery.data?.kernelSidebarTree ?? [];
      const flattened = buildPickerTreeItems(
        buildPageTreeProjectionItems(tree),
        excluded,
      );

      for (const item of flattened) {
        if (excluded.has(item.id)) continue;
        result.push({
          kind: "doc",
          id: item.id,
          title: item.title,
          depth: item.depth,
        });
      }

      return result;
    }

    const rawList = data?.results?.length ? data?.results : data?.recent ?? [];
    for (const r of rawList) {
      if (!r || excluded.has(r.id)) continue;
      result.push({
        kind: "doc",
        id: r.id,
        title: r.title || "无标题",
        subtitle: r.matchField === "recent" ? "最近打开" : undefined,
        raw: r,
      });
    }

    return result;
  }, [allowRoot, data?.recent, data?.results, excludeIds, isEmptyQuery, mode, sidebarQuery.data?.kernelSidebarTree]);

  const pickerItemIndexByKey = useMemo(() => {
    const result = new Map<string, number>();
    items.forEach((item, index) => {
      result.set(item.kind === "root" ? PICKER_ROOT_ITEM_KEY : item.id, index);
    });
    return result;
  }, [items]);

  const placeholder = mode === "move" ? "移动到..." : "嵌入到...";
  const handlePick = useCallback(
    async (targetId: string | null) => {
      await onPick(mode, targetId);
      onOpenChange(false);
    },
    [mode, onOpenChange, onPick],
  );
  useEffect(() => {
    if (items.length === 0) {
      if (highlighted !== 0) {
        setHighlighted(0);
      }
      return;
    }
    if (highlighted >= items.length) {
      setHighlighted(items.length - 1);
    }
  }, [highlighted, items.length]);
  const handleShellPickerFocusChange = useCallback(
    (payload: { itemKey: string | null; documentId: string | null }) => {
      const nextKey = payload.itemKey ?? payload.documentId;
      if (!nextKey) {
        return;
      }
      const nextIndex = pickerItemIndexByKey.get(nextKey);
      if (typeof nextIndex === "number") {
        setHighlighted(nextIndex);
      }
    },
    [pickerItemIndexByKey],
  );
  const handlePickerKeyDown = useCallback(
    (event: KeyboardEvent) => {
      if (items.length === 0) {
        return;
      }
      if (event.key === "ArrowDown") {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
        keyboardHighlightPendingRef.current = true;
        if (canDelegatePickerKeyboardToShell) {
          queuePickerCommand("next");
          return;
        }
        setHighlighted((prev) => Math.min(items.length - 1, prev + 1));
      } else if (event.key === "ArrowUp") {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
        keyboardHighlightPendingRef.current = true;
        if (canDelegatePickerKeyboardToShell) {
          queuePickerCommand("previous");
          return;
        }
        setHighlighted((prev) => Math.max(0, prev - 1));
      } else if (event.key === "Home") {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
        keyboardHighlightPendingRef.current = true;
        if (canDelegatePickerKeyboardToShell) {
          queuePickerCommand("home");
          return;
        }
        setHighlighted(0);
      } else if (event.key === "End") {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
        keyboardHighlightPendingRef.current = true;
        if (canDelegatePickerKeyboardToShell) {
          queuePickerCommand("end");
          return;
        }
        setHighlighted(items.length - 1);
      } else if (event.key === "Enter") {
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
        if (canDelegatePickerKeyboardToShell) {
          queuePickerCommand("pick");
          return;
        }
        const picked = items[highlighted];
        if (!picked) return;
        void handlePick(picked.id);
      }
    },
    [canDelegatePickerKeyboardToShell, handlePick, highlighted, items, queuePickerCommand],
  );
  useEffect(() => {
    const input = searchInputRef.current;
    if (!input) {
      return undefined;
    }
    const onKeyDown = (event: KeyboardEvent) => {
      handlePickerKeyDown(event);
    };
    input.addEventListener("keydown", onKeyDown, true);
    return () => {
      input.removeEventListener("keydown", onKeyDown, true);
    };
  }, [handlePickerKeyDown]);
  useEffect(() => {
    if (!keyboardHighlightPendingRef.current) {
      return;
    }
    keyboardHighlightPendingRef.current = false;
    if (isEmptyQuery || treeRendererFamily !== "rust_family") {
      return;
    }
    const input = searchInputRef.current;
    if (!input) {
      return;
    }
    window.requestAnimationFrame(() => {
      const current = searchInputRef.current;
      if (!current) {
        return;
      }
      // 说明：same-origin picker shell 在搜索态会随高亮更新重新同步 iframe。
      // 这里把焦点稳回搜索框，避免第二次 ArrowDown 丢到输入框外。
      current.focus({ preventScroll: true });
      const end = current.value.length;
      try {
        current.setSelectionRange(end, end);
      } catch {
        // 说明：部分输入实现不支持 selection range，这里静默忽略即可。
      }
    });
  }, [highlighted, isEmptyQuery, treeRendererFamily]);
  const highlightedItem = items[highlighted] ?? null;
  const highlightedDocumentId = highlightedItem?.kind === "doc" ? highlightedItem.id : null;
  const activePickerItemKey =
    highlightedItem?.kind === "root"
      ? PICKER_ROOT_ITEM_KEY
      : highlightedItem?.kind === "doc"
        ? highlightedItem.id
        : null;
  const pickerFallback = (
    sidebarQuery.isLoading ? (
      <div className="p-4 text-sm text-gray-400">加载中...</div>
    ) : sidebarQuery.error ? (
      <div className="p-4 text-sm text-red-600">{String(sidebarQuery.error)}</div>
    ) : (
      <TreePickerSurface
        rendererFamily={treeRendererFamily}
        workspaceId={workspaceId}
        treeShellEnabled={isEmptyQuery}
        activePickerItemKey={activePickerItemKey}
        allowRootPick={allowRoot && mode === "move"}
        excludeIds={excludeIds}
        pickerCommand={canDelegatePickerKeyboardToShell ? pickerCommand : null}
        treeShellItems={items}
        items={items}
        highlighted={highlighted}
        onHighlight={setHighlighted}
        onPick={(targetId) => {
          void handlePick(targetId);
        }}
        onPickerFocusChange={canDelegatePickerKeyboardToShell ? handleShellPickerFocusChange : undefined}
      />
    )
  );

  return (
    <div className="flex h-[520px] flex-col">
      <div className="border-b border-[#eef2ff] p-4">
        <Tabs value={mode} onValueChange={handleModeChange}>
          <TabsList className="w-full">
            {modes.includes("move") && (
              <TabsTrigger value="move" className="flex-1">
                移动到
              </TabsTrigger>
            )}
            {modes.includes("embed") && (
              <TabsTrigger value="embed" className="flex-1">
                嵌入到
              </TabsTrigger>
            )}
          </TabsList>
          <TabsContent value={mode} className="mt-4">
            <div className="relative">
              <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
              <Input
                ref={searchInputRef}
                value={query}
                onChange={(e) => handleQueryChange(e.target.value)}
                placeholder={placeholder}
                className="h-10 rounded-xl border-[#e2e8f0] pl-9 text-sm"
              />
            </div>
          </TabsContent>
        </Tabs>
      </div>

      <div className="flex-1 overflow-y-auto">
        {!workspaceId ? (
          <div className="p-4 text-sm text-gray-500">缺少 workspaceId，无法加载页面列表。</div>
        ) : isEmptyQuery ? (
          <div className="h-full p-3">{pickerFallback}</div>
        ) : isLoading ? (
          <div className="p-4 text-sm text-gray-400">加载中...</div>
        ) : error ? (
          <div className="p-4 text-sm text-red-600">{String(error)}</div>
        ) : (
          <TreePickerSurface
            rendererFamily={treeRendererFamily}
            workspaceId={workspaceId}
            treeShellEnabled={Boolean(workspaceId)}
            activeDocumentId={highlightedDocumentId}
            activePickerItemKey={activePickerItemKey}
            allowRootPick={false}
            excludeIds={excludeIds}
            pickerCommand={canDelegatePickerKeyboardToShell ? pickerCommand : null}
            treeShellItems={items}
            items={items}
            highlighted={highlighted}
            className="py-2"
            onHighlight={setHighlighted}
            onPick={(targetId) => {
              void handlePick(targetId);
            }}
            onPickerFocusChange={canDelegatePickerKeyboardToShell ? handleShellPickerFocusChange : undefined}
          />
        )}
      </div>
    </div>
  );
}
