import { useCallback, useRef, useState } from "react";
import {
  ENTRANCE_ANIMATION_BASE_DELAY_MS,
  MAX_ENTRANCE_DELAY_MS,
} from "@/shared/entranceAnimation";

/** حداکثر زمان پخش انیمیشن ورود (برای برداشتن حالت play) */
const MAX_ENTRANCE_PLAY_MS =
  ENTRANCE_ANIMATION_BASE_DELAY_MS +
  MAX_ENTRANCE_DELAY_MS +
  4000 +
  1200;

export type EntrancePhase = "idle" | "play" | "settled";

type PageRef = { id: number };

type Options = {
  pages: PageRef[];
};

/**
 * کنترل یک‌بار پخش انیمیشن ورود هر صفحه — state در والد نگه‌داری می‌شود
 * تا با remount شدن BookPage هنگام ورق‌خوردن دوباره اجرا نشود.
 *
 * محاسبهٔ اینکه «کدام صفحات منطقی در اسپرد جاری قابل‌مشاهده‌اند» بر عهدهٔ صدا‌زننده
 * (BookViewer) است: در کتاب RTL، ایندکس نمایشی (flip index) و ایندکس منطقی صفحه
 * برعکس هم می‌شوند، پس جفت‌سازی باید در فضای نمایشی انجام و سپس به منطقی تبدیل شود.
 * اینجا فقط لیست ایندکس‌های منطقیِ از قبل‌محاسبه‌شده را می‌گیرد.
 */
export function useBookEntranceController({ pages }: Options) {
  const playedPageIdsRef = useRef(new Set<number>());
  const [playingPageIds, setPlayingPageIds] = useState<ReadonlySet<number>>(() => new Set());
  const playTimersRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());

  const clearPlayTimer = useCallback((pageId: number) => {
    const t = playTimersRef.current.get(pageId);
    if (t) {
      clearTimeout(t);
      playTimersRef.current.delete(pageId);
    }
  }, []);

  const finishPlaying = useCallback((pageId: number) => {
    clearPlayTimer(pageId);
    setPlayingPageIds((prev) => {
      if (!prev.has(pageId)) return prev;
      const next = new Set(prev);
      next.delete(pageId);
      return next;
    });
  }, [clearPlayTimer]);

  const scheduleEntranceForIndices = useCallback(
    (visibleLogicalIndices: number[]) => {
      const visibleIds = new Set(
        visibleLogicalIndices
          .map((i) => pages[i]?.id)
          .filter((id): id is number => id != null),
      );

      const newlyPlaying: number[] = [];

      for (const i of visibleLogicalIndices) {
        const page = pages[i];
        if (!page) continue;
        if (playedPageIdsRef.current.has(page.id)) continue;

        playedPageIdsRef.current.add(page.id);
        newlyPlaying.push(page.id);
      }

      setPlayingPageIds((prev) => {
        const next = new Set<number>();
        for (const id of prev) {
          if (visibleIds.has(id)) next.add(id);
        }
        for (const id of newlyPlaying) next.add(id);
        if (
          next.size === prev.size &&
          newlyPlaying.every((id) => prev.has(id))
        ) {
          return prev;
        }
        return next;
      });

      if (newlyPlaying.length === 0) return;

      for (const pageId of newlyPlaying) {
        clearPlayTimer(pageId);
        playTimersRef.current.set(
          pageId,
          setTimeout(() => finishPlaying(pageId), MAX_ENTRANCE_PLAY_MS),
        );
      }
    },
    [pages, clearPlayTimer, finishPlaying],
  );

  const getEntrancePhase = useCallback(
    (pageId: number): EntrancePhase => {
      if (playingPageIds.has(pageId)) return "play";
      if (playedPageIdsRef.current.has(pageId)) return "settled";
      return "idle";
    },
    [playingPageIds],
  );

  const reset = useCallback(() => {
    for (const id of playTimersRef.current.keys()) {
      clearPlayTimer(id);
    }
    playedPageIdsRef.current.clear();
    setPlayingPageIds(new Set());
  }, [clearPlayTimer]);

  return {
    scheduleEntranceForIndices,
    getEntrancePhase,
    reset,
  };
}
