import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { buildSidebarDataSyncKey } from "@/components/sidebar/sidebar-sync";
import type { SidebarInitialData } from "@/components/sidebar/types";
import { useConvexSidebarData } from "@/hooks/use-convex-sidebar-data";

export interface SidebarDataResult {
  data: SidebarInitialData;
  isLoading: boolean;
  error: Error | null;
  refetch: () => Promise<unknown>;
  source: "convex-live" | "http-fallback" | "initial";
}

const STABLE_SIDEBAR_CACHE_LIMIT = 12;
const stableSidebarDataCache = new Map<string, SidebarInitialData>();

function getStableSidebarData(syncKey: string, data: SidebarInitialData): SidebarInitialData {
  const cached = stableSidebarDataCache.get(syncKey);
  if (cached) {
    return cached;
  }
  stableSidebarDataCache.set(syncKey, data);
  if (stableSidebarDataCache.size > STABLE_SIDEBAR_CACHE_LIMIT) {
    const oldestKey = stableSidebarDataCache.keys().next().value;
    if (typeof oldestKey === "string") {
      stableSidebarDataCache.delete(oldestKey);
    }
  }
  return data;
}

async function requestSidebarData(workspaceId: string): Promise<SidebarInitialData> {
  const response = await fetch(`/api/sidebar?workspaceId=${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();
}

export function useSidebarData(initialData: SidebarInitialData): SidebarDataResult {
  const workspaceId = initialData.activeWorkspaceId;
  const convexSidebar = useConvexSidebarData(workspaceId);
  const shouldUseHttpFallback =
    !convexSidebar.hasLiveSubscription && convexSidebar.canUseHttpFallback;
  const [manualSnapshotState, setManualSnapshotState] = useState<{
    workspaceId: string;
    data: SidebarInitialData | null;
    baseSyncKey: string | null;
  }>({
    workspaceId,
    data: null,
    baseSyncKey: null,
  });

  const httpQuery = useQuery({
    queryKey: ["sidebar", workspaceId],
    queryFn: () => requestSidebarData(workspaceId),
    initialData,
    staleTime: 1000 * 60,
    enabled: shouldUseHttpFallback,
  });

  const manualSnapshot =
    manualSnapshotState.workspaceId === workspaceId
      ? manualSnapshotState.data
      : null;
  const manualSnapshotBaseSyncKey =
    manualSnapshotState.workspaceId === workspaceId
      ? manualSnapshotState.baseSyncKey
      : null;

  const baseLiveData = convexSidebar.data ?? httpQuery.data ?? initialData;
  const baseLiveDataSyncKey = useMemo(
    () => buildSidebarDataSyncKey(baseLiveData),
    [baseLiveData],
  );
  const manualSnapshotSyncKey = useMemo(
    () => (manualSnapshot ? buildSidebarDataSyncKey(manualSnapshot) : null),
    [manualSnapshot],
  );
  const liveData = useMemo(() => {
    if (!manualSnapshot) {
      return baseLiveData;
    }
    if (
      manualSnapshotBaseSyncKey === baseLiveDataSyncKey &&
      manualSnapshotSyncKey &&
      manualSnapshotSyncKey !== baseLiveDataSyncKey
    ) {
      return manualSnapshot;
    }
    return baseLiveData;
  }, [
    baseLiveData,
    baseLiveDataSyncKey,
    manualSnapshot,
    manualSnapshotBaseSyncKey,
    manualSnapshotSyncKey,
  ]);
  const isLoading =
    convexSidebar.hasLiveSubscription
      ? convexSidebar.isLoading
      : shouldUseHttpFallback
        ? httpQuery.isLoading
        : false;
  const source: SidebarDataResult["source"] = convexSidebar.data
    ? "convex-live"
    : shouldUseHttpFallback && httpQuery.data
      ? "http-fallback"
      : "initial";
  const error = convexSidebar.error ?? httpQuery.error ?? null;
  const liveDataRef = useRef(liveData);
  const convexRefetchRef = useRef(convexSidebar.refetch);
  const httpRefetchRef = useRef(httpQuery.refetch);
  const liveDataSyncKey = useMemo(() => buildSidebarDataSyncKey(liveData), [liveData]);

  useEffect(() => {
    liveDataRef.current = liveData;
  }, [liveData]);

  useEffect(() => {
    convexRefetchRef.current = convexSidebar.refetch;
  }, [convexSidebar]);

  useEffect(() => {
    httpRefetchRef.current = httpQuery.refetch;
  }, [httpQuery]);

  const refetch = useCallback(async () => {
    if (workspaceId) {
      try {
        const refreshedSnapshot = await requestSidebarData(workspaceId);
        setManualSnapshotState({
          workspaceId,
          data: refreshedSnapshot,
          baseSyncKey: buildSidebarDataSyncKey(liveDataRef.current),
        });
        return refreshedSnapshot;
      } catch {
      }
    }
    if (convexSidebar.hasLiveSubscription) {
      await convexRefetchRef.current();
      return liveDataRef.current;
    }
    if (shouldUseHttpFallback) {
      return httpRefetchRef.current();
    }
    return liveDataRef.current;
  }, [
    convexSidebar.hasLiveSubscription,
    shouldUseHttpFallback,
    workspaceId,
  ]);
  const stableLiveData = getStableSidebarData(liveDataSyncKey, liveData);

  return useMemo<SidebarDataResult>(() => {
    return {
      data: stableLiveData,
      isLoading,
      error,
      refetch,
      source,
    };
  }, [
    error,
    isLoading,
    refetch,
    stableLiveData,
    source,
  ]);
}
