"use client";

import { useEffect } from "react";
import { useSession } from "next-auth/react";
import { useQueryClient } from "@tanstack/react-query";
import { prefetchDashboardSections } from "@/features/dashboard/api/prefetch-dashboard-sections";
import {
  fetchGroupedPipelineStages,
  fetchPipelinesClientCacheRevision,
  fetchPipelinesList,
  pipelinesKeys,
} from "@/hooks/use-pipelines-query";
import {
  readLeadsPipelineStagesReady,
  readPipelinesRevisionPayload,
  writePipelinesRevisionPayload,
} from "@/lib/query-persist-storage";

const PIPELINE_PREFETCH_STALE_MS = 1000 * 60 * 60 * 24 * 365;

/** Defer non-critical work so first paint / session hydration stays light. */
function runWhenIdle(fn: () => void): void {
  if (typeof requestIdleCallback !== "undefined") {
    requestIdleCallback(() => fn(), { timeout: 4000 });
  } else {
    setTimeout(fn, 0);
  }
}

function prefetchGroupedLeadStages(
  queryClient: ReturnType<typeof useQueryClient>,
): Promise<unknown> {
  return queryClient.prefetchQuery({
    queryKey: pipelinesKeys.grouped({ stageType: "Lead" }),
    queryFn: () => fetchGroupedPipelineStages({ stageType: "Lead" }),
    staleTime: PIPELINE_PREFETCH_STALE_MS,
  });
}

function prefetchGroupedDealStages(
  queryClient: ReturnType<typeof useQueryClient>,
): Promise<unknown> {
  return queryClient.prefetchQuery({
    queryKey: pipelinesKeys.grouped({ stageType: "Deal" }),
    queryFn: () => fetchGroupedPipelineStages({ stageType: "Deal" }),
    staleTime: PIPELINE_PREFETCH_STALE_MS,
  });
}

async function prefetchAllPipelineCaches(queryClient: ReturnType<typeof useQueryClient>) {
  await queryClient.prefetchQuery({
    queryKey: pipelinesKeys.lists(),
    queryFn: fetchPipelinesList,
    staleTime: PIPELINE_PREFETCH_STALE_MS,
  });
  void prefetchGroupedLeadStages(queryClient);
  runWhenIdle(() => {
    void new Promise<void>((r) => setTimeout(r, 160)).then(() =>
      prefetchGroupedDealStages(queryClient),
    );
  });
}

/**
 * After login: call `/pipelines/client-cache-revision` once, compare to sessionStorage,
 * and prefetch only buckets whose revision changed (or first visit / user switch).
 * Logout clears stored revision via `clientSignOut` so the next login loads fresh.
 */
export function BackgroundPrefetcher() {
  const { data: session, status } = useSession();
  const queryClient = useQueryClient();

  const sessionUser = session?.user as
    | { email?: string | null; id?: string | null }
    | undefined;
  const sessionUserKey =
    sessionUser?.email?.trim().toLowerCase() ??
    (typeof sessionUser?.id === "string" && sessionUser.id.trim()
      ? `id:${sessionUser.id.trim()}`
      : "");

  useEffect(() => {
    if (status !== "authenticated" || !sessionUserKey) return;

    let cancelled = false;

    void (async () => {
      try {
        const remote = await fetchPipelinesClientCacheRevision();
        if (cancelled) return;

        const prev = readPipelinesRevisionPayload();
        const userOk = prev?.userKey === sessionUserKey;

        const needList =
          !userOk || !prev || prev.pipelinesList !== remote.pipelinesList;
        const needLead =
          !userOk || !prev || prev.stagesGroupedLead !== remote.stagesGroupedLead;
        const needDeal =
          !userOk || !prev || prev.stagesGroupedDeal !== remote.stagesGroupedDeal;

        const tasks: Promise<unknown>[] = [];
        if (needList) {
          tasks.push(
            queryClient.prefetchQuery({
              queryKey: pipelinesKeys.lists(),
              queryFn: fetchPipelinesList,
              staleTime: PIPELINE_PREFETCH_STALE_MS,
            }),
          );
        }
        await Promise.all(tasks);

        const cachedLeadGrouped = queryClient.getQueryData<unknown[]>(
          pipelinesKeys.grouped({ stageType: "Lead" }),
        );
        const hasLeadGroupedCache =
          Array.isArray(cachedLeadGrouped) && cachedLeadGrouped.length > 0;
        const warm = readLeadsPipelineStagesReady();
        const warmMatches =
          warm?.userKey === sessionUserKey &&
          warm?.stagesGroupedLeadRev === remote.stagesGroupedLead;
        /** Skip duplicate `/pipelines/stages-grouped?stageType=Lead` when login or board already hydrated TanStack for this revision. */
        const skipLeadGroupedPrefetch =
          hasLeadGroupedCache && (!needLead || warmMatches);

        // Lead stages: prefetch immediately so `/leads` sync is not blocked on idle.
        if (!skipLeadGroupedPrefetch) {
          void prefetchGroupedLeadStages(queryClient);
        }
        // Deal stages: defer to idle + small delay to avoid stacking with Lead on cold cache.
        if (needDeal) {
          runWhenIdle(() => {
            void new Promise<void>((r) => setTimeout(r, needLead ? 160 : 0)).then(() =>
              prefetchGroupedDealStages(queryClient),
            );
          });
        }

        if (!cancelled && typeof window !== "undefined") {
          writePipelinesRevisionPayload({
            userKey: sessionUserKey,
            pipelinesList: remote.pipelinesList,
            stagesGroupedLead: remote.stagesGroupedLead,
            stagesGroupedDeal: remote.stagesGroupedDeal,
          });
        }

        await prefetchDashboardSections(queryClient, "Lead", undefined);
      } catch {
        if (cancelled) return;
        try {
          await prefetchAllPipelineCaches(queryClient);
          const remote = await fetchPipelinesClientCacheRevision();
          if (!cancelled && typeof window !== "undefined") {
            writePipelinesRevisionPayload({
              userKey: sessionUserKey,
              pipelinesList: remote.pipelinesList,
              stagesGroupedLead: remote.stagesGroupedLead,
              stagesGroupedDeal: remote.stagesGroupedDeal,
            });
          }
        } catch {
          // non-fatal — pages fetch on demand
        }
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [status, sessionUserKey, queryClient]);

  return null;
}
