"use client";

import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Loader2, RotateCw } from "lucide-react";
import { useConvexAuth, useMutation, useQuery } from "convex/react";
import type { DocumentTable } from "@/types/online-table";
import {
  DEFAULT_TABLE_COLUMNS,
  DEFAULT_TABLE_ROWS,
  DEFAULT_TABLE_SCHEMA,
  createDefaultTableSnapshot,
  getDocumentTable,
  saveOnlineTable,
} from "@/lib/online-table";
import { api } from "@/lib/convex/api";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { useLuckysheetLoader } from "@/components/online-table/useLuckysheetLoader";
import { useDebouncedCallback } from "@/hooks/use-debounced-callback";
import { extractRowsForPreview } from "@/components/online-table/utils";

type LuckysheetSelection =
  | {
      row?: [number, number];
      column?: [number, number];
      row_focus?: number;
      column_focus?: number;
    }
  | undefined;

const isPrintableKey = (event: KeyboardEvent) => {
  if (event.defaultPrevented) return false;
  if (event.metaKey || event.ctrlKey || event.altKey) return false;
  if (event.key === "Enter" || event.key === "Tab" || event.key === "Escape") return false;
  if (event.key.length === 1) return true;
  return event.key === "Process" || event.key === "Unidentified";
};

const isInlineEditorVisible = () => {
  const inputBox = document.getElementById("luckysheet-input-box");
  if (!inputBox) {
    return false;
  }
  const style = window.getComputedStyle(inputBox);
  return style.top !== "-10000px" && style.display !== "none";
};

interface HeadlessTableViewerProps {
  tableId: string;
  embed?: boolean;
  editable?: boolean;
}

const VIEWER_CONTAINER_PREFIX = "headless-table-viewer-";

const HeadlessTableViewer: React.FC<HeadlessTableViewerProps> = ({ tableId, embed = false, editable }) => {
  const containerId = useMemo(() => `${VIEWER_CONTAINER_PREFIX}${tableId}`, [tableId]);
  const containerRef = useRef<HTMLDivElement>(null);
  const isLuckysheetReady = useLuckysheetLoader();
  const [table, setTable] = useState<DocumentTable | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [reloadVersion, setReloadVersion] = useState(0);
  const [isSaving, setIsSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);
  const [showSavingHint, setShowSavingHint] = useState(false);
  const savingHintTimerRef = useRef<number | null>(null);
  const lastLocalPersistAtRef = useRef<number>(0);

  const convexEnabled = isConvexEnabled();
  const { isAuthenticated } = useConvexAuth();
  const currentUser = useQuery(api.users.currentUser, convexEnabled && isAuthenticated ? {} : "skip");
  const userId =
    currentUser && typeof currentUser === "object" && typeof (currentUser as any)._id === "string"
      ? String((currentUser as any)._id)
      : "";

  const shouldFetchTable = Boolean(convexEnabled && userId && tableId);
  const tableFromConvex = useQuery(
    api.tables.get,
    shouldFetchTable ? { userId, tableId } : "skip",
  );
  const updateTable = useMutation(api.tables.update);

  const allowInlineEdit = editable ?? embed;

  const startSavingHint = useCallback(() => {
    if (savingHintTimerRef.current !== null) return;
    savingHintTimerRef.current = window.setTimeout(() => {
      setShowSavingHint(true);
    }, 700);
  }, []);

  const stopSavingHint = useCallback(() => {
    if (savingHintTimerRef.current !== null) {
      clearTimeout(savingHintTimerRef.current);
      savingHintTimerRef.current = null;
    }
    setShowSavingHint(false);
  }, []);

  useEffect(() => {
    let canceled = false;
    setIsLoading(true);
    setError(null);

    if (convexEnabled) {
      // Convex 模式下走 useQuery 实时订阅，这里仅维护与旧逻辑兼容的 loading/error 状态
      if (tableFromConvex === undefined) {
        // still loading
        return () => {
          canceled = true;
        };
      }
      if (!canceled) {
        if (tableFromConvex === null) {
          setTable(null);
          setError("无法加载表格数据");
        } else {
          // 可编辑内嵌视图：避免每次自动保存后立即重建 UI（会闪烁）。
          // 我们在本组件触发保存后的短时间内，忽略来自订阅的回写更新。
          if (allowInlineEdit && Date.now() - lastLocalPersistAtRef.current < 1500) {
            // ignore
          } else {
            setTable(tableFromConvex as unknown as DocumentTable);
          }
        }
        setIsLoading(false);
      }
      return () => {
        canceled = true;
      };
    }

    getDocumentTable(tableId)
      .then((data) => {
        if (!canceled) {
          setTable(data);
        }
      })
      .catch((err) => {
        console.error("加载表格失败", err);
        if (!canceled) {
          setTable(null);
          setError("无法加载表格数据");
        }
      })
      .finally(() => {
        if (!canceled) {
          setIsLoading(false);
        }
      });

    return () => {
      canceled = true;
    };
  }, [allowInlineEdit, convexEnabled, reloadVersion, tableFromConvex, tableId]);


  const focusLuckysheetEditor = useCallback(() => {
    const applyFocus = () => {
      const editor = document.getElementById("luckysheet-rich-text-editor");
      if (editor && typeof editor.focus === "function") {
        editor.focus();
        const selection = window.getSelection();
        if (selection && editor.childNodes.length > 0) {
          const range = document.createRange();
          range.selectNodeContents(editor);
          range.collapse(false);
          selection.removeAllRanges();
          selection.addRange(range);
        }
      }
    };
    requestAnimationFrame(() => {
      applyFocus();
      setTimeout(applyFocus, 0);
    });
  }, []);

  const isSingleCellSelection = useCallback((range: LuckysheetSelection[] | undefined) => {
    if (!Array.isArray(range) || range.length !== 1) return false;
    const target = range[0];
    if (!target) {
      return false;
    }
    const rowRange = target.row ?? (typeof target.row_focus === "number" ? [target.row_focus, target.row_focus] : undefined);
    const columnRange = target.column ?? (typeof target.column_focus === "number" ? [target.column_focus, target.column_focus] : undefined);
    if (!rowRange || !columnRange) {
      return false;
    }
    return rowRange[0] === rowRange[1] && columnRange[0] === columnRange[1];
  }, []);

  const tryEnterInlineEdit = useCallback(() => {
    if (!allowInlineEdit) {
      return false;
    }
    const luckysheetInstance = window.luckysheet;
    if (!luckysheetInstance || typeof luckysheetInstance.enterEditMode !== "function") {
      return false;
    }
    const selection = luckysheetInstance.getluckysheet_select_save?.();
    const normalized = Array.isArray(selection)
      ? (selection as LuckysheetSelection[])
      : selection
        ? [selection as LuckysheetSelection]
        : undefined;
    if (!isSingleCellSelection(normalized)) {
      return false;
    }
    setTimeout(() => {
      const editor = document.getElementById("luckysheet-rich-text-editor");
      if (editor && document.activeElement === editor && isInlineEditorVisible()) {
        return;
      }
      luckysheetInstance.enterEditMode?.();
      focusLuckysheetEditor();
    }, 0);
    return true;
  }, [allowInlineEdit, focusLuckysheetEditor, isSingleCellSelection]);

  const persistSnapshot = useCallback(async () => {
    if (!allowInlineEdit || !table || !window.luckysheet || typeof window.luckysheet.getluckysheetfile !== "function") {
      return;
    }
    startSavingHint();
    setIsSaving(true);
    setSaveError(null);
    try {
      const luckysheetData = window.luckysheet.getluckysheetfile?.() ?? [];
      const rows = extractRowsForPreview(
        luckysheetData,
        (table.schema?.columns ?? []).map((item) => ({ id: item.id })),
      ).filter((row) => row && typeof row === "object" && Object.keys(row).length > 0);
      const snapshot = {
        ...(table.snapshot ?? {}),
        rows,
        luckysheet: Array.isArray(luckysheetData) ? luckysheetData : table.snapshot?.luckysheet ?? [],
      };
      lastLocalPersistAtRef.current = Date.now();
      if (convexEnabled && userId) {
        await updateTable({
          userId,
          tableId,
          snapshot,
          rows,
          schema: table.schema,
        });
      } else {
        await saveOnlineTable(tableId, {
          snapshot,
          rows,
          schema: table.schema,
        });
      }
      window.dispatchEvent(new CustomEvent("online-table-saved", { detail: { tableId } }));
    } catch (err) {
      console.error("内嵌表格保存失败", err);
      setSaveError("自动保存失败");
    } finally {
      stopSavingHint();
      setIsSaving(false);
    }
  }, [allowInlineEdit, convexEnabled, startSavingHint, stopSavingHint, table, tableId, updateTable, userId]);

  const debouncedPersist = useDebouncedCallback(() => {
    void persistSnapshot();
  }, 1200);

  useEffect(() => {
    return () => {
      debouncedPersist.cancel();
      stopSavingHint();
    };
  }, [debouncedPersist, stopSavingHint]);

  useEffect(() => {
    if (!tableId) return;
    // Supabase 已移除：实时订阅由 Convex useQuery 承担（见上方 tableFromConvex）
  }, [tableId]);

  useEffect(() => {
    if (!isLuckysheetReady || !table || !containerRef.current || !window.luckysheet) {
      return;
    }

    if (typeof window.luckysheet.destroy === "function") {
      window.luckysheet.destroy(containerId);
    }
    containerRef.current.innerHTML = "";

    const sheets =
      (table.snapshot?.luckysheet && Array.isArray(table.snapshot.luckysheet) && table.snapshot.luckysheet.length > 0)
        ? table.snapshot.luckysheet
        : (createDefaultTableSnapshot(table.schema ?? DEFAULT_TABLE_SCHEMA).luckysheet ?? []);

    window.luckysheet?.create?.({
      container: containerId,
      title: table.title ?? tableId,
      lang: "zh",
      showinfobar: false,
      showtoolbar: false,
      showsheetbar: sheets.length > 1,
      showstatisticBar: false,
      allowEdit: allowInlineEdit,
      allowUpdate: false,
      enableAddBackTop: false,
      enableAddRow: false,
      row: DEFAULT_TABLE_ROWS,
      column: DEFAULT_TABLE_COLUMNS,
      data: sheets,
      pointEdit: allowInlineEdit,
      pointEditZoom: window.devicePixelRatio ?? 1,
      pointEditUpdate: allowInlineEdit
        ? () => {
            debouncedPersist();
          }
        : undefined,
      hook: allowInlineEdit
        ? {
            updated: () => {
              debouncedPersist();
            },
          }
        : undefined,
    } as any);

    return () => {
      if (window.luckysheet && typeof window.luckysheet.destroy === "function") {
        window.luckysheet.destroy(containerId);
      }
    };
  }, [allowInlineEdit, containerId, debouncedPersist, isLuckysheetReady, table, tableId]);

  useEffect(() => {
    if (!allowInlineEdit || !isLuckysheetReady) {
      return;
    }
    const container = document.getElementById(containerId);
    if (!container) {
      return;
    }
    const handlePointerUp: EventListener = (event) => {
      const target = event.target instanceof Node ? event.target : null;
      if (target && !container.contains(target)) {
        return;
      }
      tryEnterInlineEdit();
    };
    const events = ["pointerup", "mouseup", "touchend"] as const;
    events.forEach((eventName) => container.addEventListener(eventName, handlePointerUp, true));
    return () => {
      events.forEach((eventName) => container.removeEventListener(eventName, handlePointerUp, true));
    };
  }, [allowInlineEdit, containerId, isLuckysheetReady, tryEnterInlineEdit]);

  useEffect(() => {
    if (!allowInlineEdit || !isLuckysheetReady) {
      return;
    }
    const handleKeydown = (event: KeyboardEvent) => {
      if (!isPrintableKey(event)) {
        return;
      }
      tryEnterInlineEdit();
    };
    const handleCompositionStart = () => {
      tryEnterInlineEdit();
    };
    window.addEventListener("keydown", handleKeydown, true);
    window.addEventListener("compositionstart", handleCompositionStart, true);
    return () => {
      window.removeEventListener("keydown", handleKeydown, true);
      window.removeEventListener("compositionstart", handleCompositionStart, true);
    };
  }, [allowInlineEdit, isLuckysheetReady, tryEnterInlineEdit]);

  const overlayVisible = isLoading || !isLuckysheetReady;
  const overlayText = !isLuckysheetReady ? "正在加载 Luckysheet 资源..." : "正在加载表格数据...";

  const embedContainerStyle = embed
    ? { height: "360px", minHeight: "360px", width: "100%", overflow: "hidden" as const }
    : undefined;

  useEffect(() => {
    if (!embed) return;
    const prevDocOverflow = document.documentElement.style.overflow;
    const prevBodyOverflow = document.body.style.overflow;
    document.documentElement.style.overflow = "hidden";
    document.body.style.overflow = "hidden";
    return () => {
      document.documentElement.style.overflow = prevDocOverflow;
      document.body.style.overflow = prevBodyOverflow;
    };
  }, [embed]);

  return (
    <div
      className={
        embed ? "h-full w-full bg-transparent overflow-hidden" : "min-h-screen w-full bg-white"
      }
      style={embedContainerStyle}
    >
      <div
        className={
          embed ? "relative h-full w-full overflow-hidden" : "relative h-[calc(100vh-64px)] w-full"
        }
        style={embedContainerStyle}
      >
        <div
          id={containerId}
          ref={containerRef}
          className="h-full w-full"
          style={{ display: isLuckysheetReady && !!table && !error ? "block" : "none" }}
        />

        {overlayVisible && (
          <div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-white/90">
            <Loader2 className="h-6 w-6 animate-spin text-gray-500" />
            <span className="text-sm text-gray-500">{overlayText}</span>
          </div>
        )}

        {error && !overlayVisible && (
          <div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-white/95 text-red-500">
            <span className="text-sm">{error}</span>
            <button
              type="button"
              className="flex items-center gap-2 rounded-md border border-red-300 px-3 py-1 text-sm"
              onClick={() => setReloadVersion((value) => value + 1)}
            >
              <RotateCw className="h-4 w-4" />
              重试
            </button>
          </div>
        )}
        {allowInlineEdit && ((isSaving && showSavingHint) || saveError) && (
          <div className="pointer-events-none absolute bottom-2 right-3 flex flex-col items-end text-xs">
            {isSaving && showSavingHint && (
              <span className="rounded-md bg-white/80 px-2 py-0.5 text-gray-500 shadow">同步中...</span>
            )}
            {saveError && <span className="mt-1 rounded-md bg-white/80 px-2 py-0.5 text-red-500 shadow">{saveError}</span>}
          </div>
        )}
      </div>
    </div>
  );
};

export default HeadlessTableViewer;

