import { getPaperDimensions } from "@/config/paperSizes";
import { clx } from "@/helpers/utils";
import type { DocumentSettings } from "@/pages/editor/store/editorStore";
import { useBookEntranceController } from "@/pages/viewer/hooks/useBookEntranceController";
import { useIsBrowserFullscreen } from "@/pages/viewer/hooks/useIsBrowserFullscreen";
import { useViewerViewport } from "@/pages/viewer/hooks/useViewerViewport";
import { isLegacyIOSSafari } from "@/pages/viewer/utils/isLegacyIOSSafari";
import { resolvePageBackground } from "@/pages/viewer/utils/pageBackground";
import { getVisiblePageIndices } from "@/pages/viewer/utils/visiblePageIndices";
import { toggleViewerFullscreen } from "@/pages/viewer/utils/viewerFullscreen";
import { ArrowLeft2, ArrowRight2, Maximize4, Pause, Play, RowVertical } from "iconsax-react";
import { type FC, useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
import HTMLFlipBook from "react-pageflip";
import { type PageData } from "../types";
import BookPage from "./BookPage";
import Magnifier from "./Magnifier/Magnifier";
import ZoomButton from "./Toolbar/ZoomButton";

/** فاصله پیش‌فرض بین هر ورق در پخش خودکار (میلی‌ثانیه) */
const AUTO_PLAY_INTERVAL_MS = 3000;

const VIEWER_SCALE = 0.5;
/** فاصلهٔ کتاب از بالای صفحه (پیکسل) */
const BOOK_TOP_GAP_DESKTOP = 48;
const BOOK_TOP_GAP_MOBILE = 32;
/** نسخهٔ فعلی `page-flip.mp3` دو ضربهٔ ورق پشت‌هم دارد؛ فقط تا این سهم از طول پخش می‌شود */
const PAGE_FLIP_SOUND_PLAY_FRACTION = 0.5;
/** هم‌راستا با `md` تیلویند (768px) — موبایل: زیر این عرض */
const MOBILE_QUERY = "(min-width: 768px)";
/** شناسهٔ صفحهٔ خالیِ کمکی برای اصلاح جفت‌سازی جلد در کتاب RTL با تعداد صفحات فرد (هرگز به کاربر نمایش داده نمی‌شود) */
const RTL_COVER_PAD_PAGE_ID = -1;

function subscribeDesktopMql(callback: () => void) {
  const mq = window.matchMedia(MOBILE_QUERY);
  mq.addEventListener("change", callback);
  return () => mq.removeEventListener("change", callback);
}

function useIsDesktop() {
  return useSyncExternalStore(
    subscribeDesktopMql,
    () => window.matchMedia(MOBILE_QUERY).matches,
    () => true,
  );
}

function useLegacyIOSSafari() {
  return useSyncExternalStore(
    () => () => {},
    isLegacyIOSSafari,
    () => false,
  );
}

export type BookViewerProps = {
  pages: PageData[];
  catalogSize?: string;
  documentSettings?: Partial<DocumentSettings>;
};

interface PageFlipAPI {
  flipNext: () => void;
  flipPrev: () => void;
  turnToPage: (page: number) => void;
  getCurrentPageIndex?: () => number;
}

interface FlipBookInstance {
  pageFlip: () => PageFlipAPI | undefined;
}

interface FlipEvent {
  data: number;
}

type PageFlipInitEvent = { data: { page: number; mode: string } };
type PageFlipStateEvent = { data: string };

/** مختصات داخلی رندر کتاب (همان فضایی که getBoundsRect و flipNext استفاده می‌کنند) */
type FlipBookRect = { left: number; top: number; width: number; height: number; pageWidth: number };

type PageFlipWithFlipController = PageFlipAPI & {
  getBoundsRect: () => FlipBookRect;
  getFlipController: () => { flip: (p: { x: number; y: number }) => void };
};

type AutoPlayToggleButtonProps = {
  isActive: boolean;
  onToggle: () => void;
};

const AutoPlayToggleButton: FC<AutoPlayToggleButtonProps> = ({ isActive, onToggle }) => (
  <button
    type="button"
    onClick={onToggle}
    className="px-3 py-1.5 text-xs md:text-sm font-medium inline-flex items-center justify-center gap-1.5 rounded-full border border-gray-300 hover:bg-gray-100 active:bg-gray-200 transition-all"
    aria-label={isActive ? "توقف پخش خودکار" : "شروع پخش خودکار"}
  >
    {isActive ? <Pause color="black" size={16} className="text-gray-700 md:w-[18px] md:h-[18px]" /> : <Play color="black" size={16} className="text-gray-700 md:w-[18px] md:h-[18px]" />}
    <span>{isActive ? "توقف پخش" : "پخش خودکار"}</span>
  </button>
);

/**
 * page-flip داخل flipPrev با x=10 ثابت می‌زند؛ با disableFlipByClick آزمایش گوشه رد می‌شود
 * (چون bookPos.x = 10 - rect.left معمولاً ≤ 0). flipNext همان rect.left را جمع می‌کند.
 */
function triggerFlipPrev(api: PageFlipWithFlipController | undefined) {
  if (!api?.getBoundsRect || !api.getFlipController) {
    api?.flipPrev();
    return;
  }
  const rect = api.getBoundsRect();
  api.getFlipController().flip({
    x: rect.left + 12,
    y: rect.top + 2,
  });
}

/**
 * کامپوننت اصلی کتابخوان با استفاده از react-pageflip
 * این کامپوننت از HTMLFlipBook استفاده می‌کند که یک wrapper برای PageFlip است
 * از HTML برای رندر صفحات استفاده می‌شود (نه Canvas) برای سازگاری با Konva در آینده
 */
const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings }) => {
  const bookRef = useRef<FlipBookInstance | null>(null);
  const bookAreaRef = useRef<HTMLDivElement | null>(null);
  const flipbookWrapperRef = useRef<HTMLDivElement | null>(null);
  const spineOverlayRef = useRef<HTMLDivElement | null>(null);
  const pageFlipHandlerRef = useRef<(e: FlipEvent) => void>(() => {});
  const [currentPage, setCurrentPage] = useState(0);
  const [isAutoPlayActive, setIsAutoPlayActive] = useState(false);
  const [startPage, setStartPage] = useState(0);
  const [magnifierEnabled, setMagnifierEnabled] = useState(false);
  /** ref نه state — تغییر z-index هنگام hover ورق نباید BookPage را remount/re-render کند (انیمیشن ورود دوباره اجرا می‌شد) */
  const isBookFlippingRef = useRef(false);
  const setBookFlippingVisual = useCallback((flipping: boolean) => {
    if (isBookFlippingRef.current === flipping) return;
    isBookFlippingRef.current = flipping;
    flipbookWrapperRef.current?.classList.toggle("relative", flipping);
    flipbookWrapperRef.current?.classList.toggle("z-10", flipping);
    flipbookWrapperRef.current?.classList.toggle("flipbook-flipping", flipping);
    spineOverlayRef.current?.classList.toggle("z-50", !flipping);
    spineOverlayRef.current?.classList.toggle("z-0", flipping);
  }, []);
  const isDesktop = useIsDesktop();
  const legacyIOS = useLegacyIOSSafari();
  const isBrowserFullscreen = useIsBrowserFullscreen();

  const autoPlay = documentSettings?.autoPlay ?? false;
  const pageFlipSound = documentSettings?.pageFlipSound ?? true;
  const leftToRightFlip = documentSettings?.leftToRightFlip ?? false;
  const displayStyle = documentSettings?.displayStyle ?? "double";
  const usePortrait = !isDesktop || displayStyle === "single";
  /** react-pageflip از RTL پشتیبانی نمی‌کند؛ ترتیب صفحات برعکس + شروع از آخر */
  const isRtlBook = !leftToRightFlip;
  /**
   * page-flip فقط صفحهٔ با ایندکس 0 را به‌عنوان جلد تکی در نظر می‌گیرد. بعد از برعکس‌کردن
   * آرایه برای RTL، جلد واقعی (صفحهٔ منطقی 0) در انتهای آرایه قرار می‌گیرد و اگر تعداد کل
   * صفحات فرد باشد، جفت‌سازی داخلی کتابخانه آن را با صفحهٔ بعدی هم‌اسپرد می‌کند (به‌جای تکی).
   * با افزودن یک صفحهٔ خالی نامرئی به ابتدای آرایهٔ برعکس‌شده، توازن جفت‌سازی طوری اصلاح می‌شود
   * که جلد واقعی همیشه تکی نمایش داده شود.
   */
  const needsRtlCoverPad = isRtlBook && !usePortrait && pages.length > 1 && pages.length % 2 === 1;
  const displayPages = useMemo(() => {
    if (!isRtlBook) return pages;
    const reversed = [...pages].reverse();
    if (!needsRtlCoverPad) return reversed;
    const fillerPage: PageData = {
      id: RTL_COVER_PAD_PAGE_ID,
      width: pages[0]?.width ?? 794,
      height: pages[0]?.height ?? 1123,
      elements: [],
      backgroundType: "color",
      backgroundColor: "#ffffff",
    };
    return [fillerPage, ...reversed];
  }, [pages, isRtlBook, needsRtlCoverPad]);
  const flipIndexCount = displayPages.length;
  const toLogicalIndex = useCallback(
    (flipIndex: number) => {
      if (!isRtlBook) return flipIndex;
      return needsRtlCoverPad ? pages.length - flipIndex : pages.length - 1 - flipIndex;
    },
    [isRtlBook, needsRtlCoverPad, pages.length],
  );
  const toFlipIndex = useCallback(
    (logicalIndex: number) => {
      if (!isRtlBook) return logicalIndex;
      return needsRtlCoverPad ? pages.length - logicalIndex : pages.length - 1 - logicalIndex;
    },
    [isRtlBook, needsRtlCoverPad, pages.length],
  );
  const backgroundType = documentSettings?.backgroundType ?? "color";
  const backgroundColor = documentSettings?.backgroundColor ?? "#ffffff";
  const backgroundOpacity = documentSettings?.backgroundOpacity ?? 100;
  const backgroundGradient = documentSettings?.backgroundGradient;
  const backgroundImageUrl = documentSettings?.backgroundImageUrl ?? "";
  const backgroundVideoUrl = documentSettings?.backgroundVideoUrl ?? "";
  const pageBackgroundDefaults = useMemo(
    () => ({ backgroundType, backgroundColor, backgroundOpacity, backgroundGradient, backgroundImageUrl, backgroundVideoUrl }),
    [backgroundType, backgroundColor, backgroundOpacity, backgroundGradient, backgroundImageUrl, backgroundVideoUrl],
  );

  useEffect(() => {
    setIsAutoPlayActive(autoPlay);
  }, [autoPlay]);

  // سایز کتاب بر اساس catalogSize (A3/A4/A5)
  const { width: bookWidth, height: bookHeight } = useMemo(() => getPaperDimensions(catalogSize ?? "a4"), [catalogSize]);
  const hasMultiplePages = pages.length > 1;
  const viewport = useViewerViewport();

  const viewportFit = useMemo(() => {
    const padX = isDesktop ? 48 : 20;
    const edgeBleed = isDesktop ? 0 : 6;
    const reservedNav = isDesktop ? 96 : 120;
    const reservedTop = isDesktop ? BOOK_TOP_GAP_DESKTOP : BOOK_TOP_GAP_MOBILE;
    const maxW = Math.max(1, viewport.w - padX - edgeBleed * 2);
    const maxH = Math.max(1, viewport.h - reservedNav - reservedTop - edgeBleed);
    const spreadCount = usePortrait ? 1 : 2;
    const basePageW = bookWidth * VIEWER_SCALE;
    const basePageH = bookHeight * VIEWER_SCALE;
    const baseSpreadW = basePageW * spreadCount;
    const scale = Math.min(maxW / baseSpreadW, maxH / basePageH);
    return {
      w: Math.max(1, Math.round(basePageW * scale)),
      h: Math.max(1, Math.round(basePageH * scale)),
      contentScale: VIEWER_SCALE * scale,
    };
  }, [isDesktop, bookWidth, bookHeight, viewport.w, viewport.h, usePortrait]);

  const pagePixelWidth = viewportFit.w;
  const pagePixelHeight = viewportFit.h;
  const contentScale = viewportFit.contentScale;
  const flipDisabledOnMobile = !isDesktop && magnifierEnabled;
  const magnifierLockedPageId = usePortrait ? (pages[currentPage]?.id ?? null) : null;

  const flipKey = `${usePortrait ? "portrait" : "spread"}-${pagePixelWidth}-${pagePixelHeight}-${flipIndexCount}`;

  const {
    scheduleEntranceForIndices,
    getEntrancePhase,
    replayEntranceForPage,
    reset: resetEntrance,
  } = useBookEntranceController({ pages });

  /**
   * ایندکس‌های منطقیِ صفحات قابل‌مشاهده در اسپرد جاری را برمی‌گرداند.
   * جفت‌سازی (کدام دو صفحه با هم دیده می‌شوند) باید در فضای نمایشیِ کتاب
   * (flip index) انجام شود، نه فضای منطقی: در کتاب RTL این دو فضا برعکس
   * هم‌اند، پس مثلاً «ایندکس منطقی + ۱» لزوماً هم‌صفحه‌ی واقعی نیست.
   */
  const getVisibleLogicalIndices = useCallback(
    (flipIdx: number): number[] => {
      const displayIndices = getVisiblePageIndices(flipIdx, flipIndexCount, {
        portrait: usePortrait,
        showCover: hasMultiplePages,
      });
      const seen = new Set<number>();
      const result: number[] = [];
      for (const di of displayIndices) {
        const logical = toLogicalIndex(di);
        if (logical >= 0 && logical < pages.length && !seen.has(logical)) {
          seen.add(logical);
          result.push(logical);
        }
      }
      return result;
    },
    [flipIndexCount, usePortrait, hasMultiplePages, toLogicalIndex, pages.length],
  );

  const commitEntranceAtCurrentSpread = useCallback(() => {
    const api = bookRef.current?.pageFlip();
    const idx = api?.getCurrentPageIndex?.();
    if (typeof idx !== "number" || flipIndexCount <= 0) return;
    const flipIdx = Math.max(0, Math.min(idx, flipIndexCount - 1));
    scheduleEntranceForIndices(getVisibleLogicalIndices(flipIdx));
  }, [flipIndexCount, scheduleEntranceForIndices, getVisibleLogicalIndices]);

  useEffect(() => {
    resetEntrance();
    const frame = requestAnimationFrame(() => {
      commitEntranceAtCurrentSpread();
    });
    return () => cancelAnimationFrame(frame);
  }, [flipKey, pages.length, pages[0]?.id, resetEntrance, commitEntranceAtCurrentSpread]);

  // اطمینان از اینکه currentPage همیشه در محدوده معتبر است
  useEffect(() => {
    if (currentPage < 0) {
      setCurrentPage(0);
    } else if (currentPage >= pages.length) {
      setCurrentPage(pages.length - 1);
    }
  }, [currentPage, pages.length]);

  const pageFlipSoundRef = useRef<HTMLAudioElement | null>(null);
  const pageFlipSoundTrimListenerRef = useRef<(() => void) | null>(null);
  const lastFlipPageRef = useRef<number | null>(null);

  useEffect(() => {
    const base = import.meta.env.BASE_URL;
    const src = `${base}${base.endsWith("/") ? "" : "/"}sounds/page-flip.mp3`;
    const audio = new Audio(src);
    audio.preload = "auto";
    pageFlipSoundRef.current = audio;
    return () => {
      const trim = pageFlipSoundTrimListenerRef.current;
      if (trim) {
        audio.removeEventListener("timeupdate", trim);
        pageFlipSoundTrimListenerRef.current = null;
      }
      audio.pause();
      pageFlipSoundRef.current = null;
    };
  }, []);

  const playPageFlipSound = useCallback(() => {
    const audio = pageFlipSoundRef.current;
    if (!audio) return;
    const prevTrim = pageFlipSoundTrimListenerRef.current;
    if (prevTrim) {
      audio.removeEventListener("timeupdate", prevTrim);
      pageFlipSoundTrimListenerRef.current = null;
    }
    const onTimeUpdate = () => {
      const d = audio.duration;
      if (!Number.isFinite(d) || d <= 0.04) return;
      const end = d * PAGE_FLIP_SOUND_PLAY_FRACTION;
      if (audio.currentTime >= end) {
        audio.pause();
        audio.currentTime = 0;
        audio.removeEventListener("timeupdate", onTimeUpdate);
        pageFlipSoundTrimListenerRef.current = null;
      }
    };
    pageFlipSoundTrimListenerRef.current = onTimeUpdate;
    try {
      audio.currentTime = 0;
      audio.addEventListener("timeupdate", onTimeUpdate);
      void audio.play().catch(() => {
        audio.removeEventListener("timeupdate", onTimeUpdate);
        pageFlipSoundTrimListenerRef.current = null;
        /* autoplay policy — معمولاً بعد از تعامل کاربر ورق می‌خورد */
      });
    } catch {
      audio.removeEventListener("timeupdate", onTimeUpdate);
      pageFlipSoundTrimListenerRef.current = null;
    }
  }, []);

  const handlePageFlip = useCallback(
    (e: FlipEvent) => {
      // react-pageflip شماره صفحه را به صورت 0-based برمی‌گرداند
      // اما باید مطمئن شویم که در محدوده معتبر است
      let flipIndex = e.data;

      // اگر flipIndex منفی است یا بزرگتر از تعداد صفحات، آن را محدود می‌کنیم
      if (flipIndex < 0) {
        flipIndex = 0;
      } else if (flipIndex >= flipIndexCount) {
        flipIndex = flipIndexCount - 1;
      }

      const pageNum = toLogicalIndex(flipIndex);

      if (pageFlipSound && lastFlipPageRef.current !== null && lastFlipPageRef.current !== pageNum) {
        playPageFlipSound();
      }
      lastFlipPageRef.current = pageNum;

      setCurrentPage(pageNum);
    },
    [flipIndexCount, pageFlipSound, playPageFlipSound, toLogicalIndex],
  );

  pageFlipHandlerRef.current = handlePageFlip;

  const onFlipForwarded = useCallback((e: FlipEvent) => {
    pageFlipHandlerRef.current(e);
  }, []);

  const syncPageIndexFromBook = useCallback(() => {
    const api = bookRef.current?.pageFlip();
    const idx = api?.getCurrentPageIndex?.();
    if (typeof idx !== "number" || flipIndexCount <= 0) return;
    const flipIdx = Math.max(0, Math.min(idx, flipIndexCount - 1));
    setCurrentPage(toLogicalIndex(flipIdx));
  }, [flipIndexCount, toLogicalIndex]);

  const handleBookInit = useCallback(
    (e: PageFlipInitEvent) => {
      const p = e.data?.page;
      if (typeof p !== "number" || flipIndexCount <= 0) return;
      const flipIdx = Math.max(0, Math.min(p, flipIndexCount - 1));
      const logicalIdx = toLogicalIndex(flipIdx);
      setCurrentPage(logicalIdx);
      lastFlipPageRef.current = logicalIdx;
      // اولین اسپرد قبل از onChangeState('read') هم باید انیمیشن ورود بگیرد
      scheduleEntranceForIndices(getVisibleLogicalIndices(flipIdx));
    },
    [flipIndexCount, scheduleEntranceForIndices, getVisibleLogicalIndices, toLogicalIndex],
  );

  const beginPageNavigation = useCallback(() => {
    if (flipDisabledOnMobile) return false;
    setBookFlippingVisual(true);
    return true;
  }, [flipDisabledOnMobile, setBookFlippingVisual]);

  /** بعد از اتمام انیمیشن ورق، ایندکس واقعی کتاب را می‌گیریم و انیمیشن ورود را یک‌بار شروع می‌کنیم */
  const handleChangeState = useCallback(
    (e: PageFlipStateEvent) => {
      if (e.data === "read") {
        setBookFlippingVisual(false);
        syncPageIndexFromBook();
        commitEntranceAtCurrentSpread();
        return;
      }
      setBookFlippingVisual(true);
    },
    [syncPageIndexFromBook, commitEntranceAtCurrentSpread, setBookFlippingVisual],
  );

  const goToNextPage = useCallback(() => {
    if (currentPage >= pages.length - 1) return;
    if (!beginPageNavigation()) return;
    const api = bookRef.current?.pageFlip() as PageFlipWithFlipController | undefined;
    if (isRtlBook) {
      triggerFlipPrev(api);
    } else {
      api?.flipNext();
    }
  }, [currentPage, pages.length, isRtlBook, beginPageNavigation]);

  const goToPrevPage = useCallback(() => {
    if (currentPage <= 0) return;
    if (!beginPageNavigation()) return;
    const api = bookRef.current?.pageFlip() as PageFlipWithFlipController | undefined;
    if (isRtlBook) {
      api?.flipNext();
    } else {
      triggerFlipPrev(api);
    }
  }, [currentPage, isRtlBook, beginPageNavigation]);

  const stopAutoPlayByUser = useCallback(() => {
    if (isAutoPlayActive) {
      setIsAutoPlayActive(false);
    }
  }, [isAutoPlayActive]);

  const toggleAutoPlay = useCallback(() => {
    if (pages.length <= 1) return;
    setIsAutoPlayActive((prev) => !prev);
  }, [pages.length]);

  const toggleMagnifier = useCallback(() => {
    setMagnifierEnabled((prev) => !prev);
  }, []);

  useEffect(() => {
    if (!magnifierEnabled) return;
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setMagnifierEnabled(false);
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [magnifierEnabled]);

  useEffect(() => {
    if (flipDisabledOnMobile && isAutoPlayActive) {
      setIsAutoPlayActive(false);
    }
  }, [flipDisabledOnMobile, isAutoPlayActive]);

  const navigateToPageIndex = useCallback(
    (targetIndex: number) => {
      const pageFlipAPI = bookRef.current?.pageFlip();
      if (!pageFlipAPI) return;
      if (!beginPageNavigation()) return;

      const logicalIdx = Math.max(0, Math.min(targetIndex, pages.length - 1));
      const flipIdx = toFlipIndex(logicalIdx);
      pageFlipAPI.turnToPage(flipIdx);
      lastFlipPageRef.current = logicalIdx;
      scheduleEntranceForIndices(getVisibleLogicalIndices(flipIdx));
    },
    [pages.length, scheduleEntranceForIndices, getVisibleLogicalIndices, toFlipIndex, beginPageNavigation],
  );

  const handleLinkClick = useCallback(
    (linkUrl: string) => {
      if (pages.length <= 1) return;
      stopAutoPlayByUser();

      if (!linkUrl.startsWith("page://")) return;
      if (flipDisabledOnMobile) return;

      const action = linkUrl.replace("page://", "");

      if (action === "next") {
        goToNextPage();
      } else if (action === "prev") {
        goToPrevPage();
      } else if (action === "first") {
        navigateToPageIndex(0);
      } else if (action === "last") {
        navigateToPageIndex(pages.length - 1);
      } else {
        const pageNum = parseInt(action, 10);
        if (!isNaN(pageNum) && pageNum >= 1 && pageNum <= pages.length) {
          navigateToPageIndex(pageNum - 1);
        }
      }
    },
    [pages.length, goToNextPage, goToPrevPage, navigateToPageIndex, stopAutoPlayByUser, flipDisabledOnMobile],
  );

  const prevFlipKeyRef = useRef(flipKey);
  useEffect(() => {
    if (prevFlipKeyRef.current !== flipKey) {
      prevFlipKeyRef.current = flipKey;
      lastFlipPageRef.current = currentPage;
      setStartPage(toFlipIndex(currentPage));
    }
  }, [flipKey, currentPage, toFlipIndex]);

  useEffect(() => {
    if (pages.length <= 0) return;
    setStartPage(toFlipIndex(0));
    setCurrentPage(0);
    lastFlipPageRef.current = 0;
  }, [pages.length, pages[0]?.id, toFlipIndex]);

  // پخش خودکار
  useEffect(() => {
    if (!isAutoPlayActive || pages.length <= 1 || flipDisabledOnMobile) return;
    const timer = setInterval(() => {
      if (currentPage >= pages.length - 1) {
        bookRef.current?.pageFlip()?.turnToPage?.(toFlipIndex(0));
        setCurrentPage(0);
        lastFlipPageRef.current = 0;
        return;
      }
      const api = bookRef.current?.pageFlip() as PageFlipWithFlipController | undefined;
      if (isRtlBook) {
        triggerFlipPrev(api);
      } else {
        api?.flipNext();
      }
    }, AUTO_PLAY_INTERVAL_MS);
    return () => clearInterval(timer);
  }, [isAutoPlayActive, currentPage, pages.length, isRtlBook, toFlipIndex, flipDisabledOnMobile]);

  return (
    <div className="flex flex-col items-center gap-4 md:gap-6 w-full h-full max-md:min-h-0 max-md:max-w-full max-md:overflow-x-hidden max-md:pb-[env(safe-area-inset-bottom,0px)]" dir="rtl">
      <div className="relative w-full flex flex-col flex-1 max-md:min-h-0 pt-8 md:pt-12 min-h-0 overflow-hidden">
        <div ref={bookAreaRef} className="relative flex flex-1 min-h-0 w-full items-center justify-center">
          {/* Border و Shadow عمودی در وسط (فقط حالت دوصفحه‌ای دسکتاپ) */}
          {!usePortrait && (
            <div
              ref={spineOverlayRef}
              className="hidden md:block absolute inset-y-0 left-1/2 -translate-x-1/2 w-px border-r border-gray-300 pointer-events-none transition-none z-50"
              style={{
                boxShadow: "-5px 0 15px rgba(0, 0, 0, 0.15), 5px 0 15px rgba(0, 0, 0, 0.15)",
              }}
            />
          )}
          {/*
                  page-flip با مختصات LTR کار می‌کند؛ direction:rtl روی روت کتاب باعث ناهماهنگی
                  ایندکس/onFlip با دکمه‌ها می‌شود. محتوای فارسی داخل BookPage با dir=rtl است.
                */}
          <div
            ref={flipbookWrapperRef}
            dir="ltr"
            className="max-w-full flex justify-center shrink-0 rounded-sm"
            style={{
              cursor: magnifierEnabled ? "zoom-in" : undefined,
              touchAction: magnifierEnabled ? "none" : undefined,
              overflow: "hidden",
              width: usePortrait ? pagePixelWidth : pagePixelWidth * 2,
              height: pagePixelHeight,
              boxShadow: isDesktop ? undefined : "0 8px 32px rgba(0, 0, 0, 0.14), 0 2px 8px rgba(0, 0, 0, 0.08)",
            }}
          >
            <HTMLFlipBook
              key={flipKey}
              ref={bookRef}
              width={pagePixelWidth}
              height={pagePixelHeight}
              size="fixed"
              minWidth={pagePixelWidth}
              minHeight={pagePixelHeight}
              maxWidth={pagePixelWidth}
              maxHeight={pagePixelHeight}
              drawShadow={!legacyIOS}
              flippingTime={800}
              usePortrait={usePortrait}
              startPage={startPage}
              autoSize={false}
              maxShadowOpacity={legacyIOS ? 0 : isDesktop ? 0.55 : 0.32}
              showCover={hasMultiplePages}
              mobileScrollSupport={!usePortrait && !magnifierEnabled}
              clickEventForward={true}
              useMouseEvents={hasMultiplePages && !magnifierEnabled}
              swipeDistance={flipDisabledOnMobile || !hasMultiplePages ? 9999 : usePortrait ? 48 : 30}
              startZIndex={1}
              showPageCorners={hasMultiplePages && !flipDisabledOnMobile}
              disableFlipByClick={true}
              className={clx(
                "flipbook-container mx-auto max-w-full",
                legacyIOS && "flipbook-legacy-ios",
                magnifierEnabled && "flipbook-magnifier-active",
              )}
              style={{}}
              onFlip={onFlipForwarded}
              onInit={handleBookInit}
              onChangeState={handleChangeState}
            >
              {displayPages.map((page) => {
                const background = resolvePageBackground(page, pageBackgroundDefaults);
                return (
                  <BookPage
                    key={page.id}
                    page={page}
                    entrancePhase={getEntrancePhase(page.id)}
                    onDeferredEntranceReady={replayEntranceForPage}
                    scale={contentScale}
                    pageWidth={pagePixelWidth}
                    pageHeight={pagePixelHeight}
                    onLinkClick={handleLinkClick}
                    backgroundType={background.backgroundType}
                    backgroundColor={background.backgroundColor}
                    backgroundGradient={background.backgroundGradient}
                    backgroundImageUrl={background.backgroundImageUrl}
                    backgroundVideoUrl={background.backgroundVideoUrl}
                    useHardPage={legacyIOS}
                  />
                );
              })}
            </HTMLFlipBook>
          </div>
          <Magnifier
            enabled={magnifierEnabled}
            containerRef={bookAreaRef}
            interactionRef={flipbookWrapperRef}
            isFlippingRef={isBookFlippingRef}
            lockedPageId={magnifierLockedPageId}
            blockFlipTouch={flipDisabledOnMobile}
            pages={displayPages}
            pageWidth={pagePixelWidth}
            pageHeight={pagePixelHeight}
            contentScale={contentScale}
            pageDefaults={pageBackgroundDefaults}
            useHardPage={legacyIOS}
            pageIndex={currentPage}
          />
        </div>
      </div>

      <div className="shrink-0 max-md:min-h-12 flex items-center gap-3 md:gap-6 bg-white rounded-full px-4 md:px-6 py-2 md:py-3 shadow-lg">
        {hasMultiplePages && (
          <>
            {/* دکمه راست: فارسی = صفحه قبل | لاتین = صفحه بعد */}
            <button
              type="button"
              onClick={() => {
                stopAutoPlayByUser();
                if (leftToRightFlip) {
                  goToNextPage();
                } else {
                  goToPrevPage();
                }
              }}
              disabled={
                flipDisabledOnMobile ||
                (leftToRightFlip ? currentPage >= pages.length - 1 : currentPage <= 0)
              }
              className="p-2 md:p-2 min-h-11 min-w-11 md:min-h-0 md:min-w-0 inline-flex items-center justify-center rounded-full hover:bg-gray-100 active:bg-gray-200 disabled:opacity-30 disabled:cursor-not-allowed transition-all"
              aria-label={leftToRightFlip ? "صفحه بعد" : "صفحه قبل"}
              title={flipDisabledOnMobile ? "برای ورق زدن ابتدا ذره‌بین را خاموش کنید" : undefined}
            >
              <ArrowRight2 color="black" size={20} className="text-gray-700 md:w-6 md:h-6" />
            </button>
          </>
        )}

        {/* شماره صفحه */}
        <div className="flex items-center gap-2 min-w-[100px] md:min-w-[120px] justify-center">
          <span className="text-xs md:text-sm text-gray-600">
            صفحه {Math.min(currentPage + 1, pages.length)} از {pages.length}
          </span>
        </div>

        {hasMultiplePages && (
          <>
            {/* دکمه چپ: فارسی = صفحه بعد | لاتین = صفحه قبل */}
            <button
              type="button"
              onClick={() => {
                stopAutoPlayByUser();
                if (leftToRightFlip) {
                  goToPrevPage();
                } else {
                  goToNextPage();
                }
              }}
              disabled={
                flipDisabledOnMobile ||
                (leftToRightFlip ? currentPage <= 0 : currentPage >= pages.length - 1)
              }
              className="p-2 md:p-2 min-h-11 min-w-11 md:min-h-0 md:min-w-0 inline-flex items-center justify-center rounded-full hover:bg-gray-100 active:bg-gray-200 disabled:opacity-30 disabled:cursor-not-allowed transition-all"
              aria-label={leftToRightFlip ? "صفحه قبل" : "صفحه بعد"}
              title={flipDisabledOnMobile ? "برای ورق زدن ابتدا ذره‌بین را خاموش کنید" : undefined}
            >
              <ArrowLeft2 color="black" size={20} className="text-gray-700 md:w-6 md:h-6" />
            </button>
          </>
        )}

        {hasMultiplePages && autoPlay && <AutoPlayToggleButton isActive={isAutoPlayActive} onToggle={toggleAutoPlay} />}

        <ZoomButton isActive={magnifierEnabled} onToggle={toggleMagnifier} />

        <button
          type="button"
          onClick={toggleViewerFullscreen}
          className="p-2 md:p-2 min-h-11 min-w-11 md:min-h-0 md:min-w-0 inline-flex items-center justify-center rounded-full hover:bg-gray-100 active:bg-gray-200 transition-all"
          aria-label={isBrowserFullscreen ? "خروج از تمام‌صفحه" : "تمام‌صفحه مرورگر"}
          title={isBrowserFullscreen ? "خروج از تمام‌صفحه" : "تمام‌صفحه مرورگر"}
        >
          {isBrowserFullscreen ? <RowVertical color="black" size={20} className="text-gray-700 md:w-6 md:h-6" /> : <Maximize4 color="black" size={20} className="text-gray-700 md:w-6 md:h-6" />}
        </button>
      </div>
    </div>
  );
};

export default BookViewer;
