• Provides state management and control methods for AniList synchronization operations. Supports batch sync, pause/resume recovery, incremental entry processing, and error tracking. Persists state to storage for recovery on app restart.

    Returns [SynchronizationState, SynchronizationActions]

    Tuple of [synchronization state, synchronization actions].

    export function useSynchronization(): [
    SynchronizationState,
    SynchronizationActions,
    ] {
    const [state, setState] = useState<SynchronizationState>({
    isActive: false,
    progress: null,
    report: null,
    error: null,
    abortController: null,
    isPaused: false,
    resumeAvailable: false,
    resumeMetadata: null,
    });
    const [failedOperations, setFailedOperations] = useState<FailedOperation[]>(
    [],
    );
    const [isLoadingFailedOps, setIsLoadingFailedOps] = useState(false);

    // Get auth state for token in retry operations
    const { authState, isOnline } = useAuthState();

    const resumeSnapshotRef = useRef<SyncResumeSnapshot | null>(null);
    const initialEntriesRef = useRef<AniListMediaEntry[]>([]);
    const uniqueMediaIdsRef = useRef<number[]>([]);
    const pauseRequestedRef = useRef(false);
    const resumeRequestedRef = useRef(false);
    const hasLoadedSnapshotRef = useRef(false);
    const { registerStateInspector: registerSyncStateInspector, recordEvent } =
    useDebugActions();
    const syncInspectorHandleRef =
    useRef<StateInspectorHandle<SyncDebugSnapshot> | null>(null);
    const syncSnapshotRef = useRef<SyncDebugSnapshot | null>(null);
    const getSyncSnapshotRef = useRef<() => SyncDebugSnapshot>(() => ({
    state: toDebugSyncState(state),
    resumeSnapshot: resumeSnapshotRef.current
    ? {
    ...resumeSnapshotRef.current,
    entries: cloneEntries(resumeSnapshotRef.current.entries),
    }
    : null,
    pendingEntriesCount: initialEntriesRef.current.length,
    uniqueMediaIds: [...uniqueMediaIdsRef.current],
    pauseRequested: pauseRequestedRef.current,
    resumeRequested: resumeRequestedRef.current,
    }));

    getSyncSnapshotRef.current = () => ({
    state: toDebugSyncState(state),
    resumeSnapshot: resumeSnapshotRef.current
    ? {
    ...resumeSnapshotRef.current,
    entries: cloneEntries(resumeSnapshotRef.current.entries),
    }
    : null,
    pendingEntriesCount: initialEntriesRef.current.length,
    uniqueMediaIds: [...uniqueMediaIdsRef.current],
    pauseRequested: pauseRequestedRef.current,
    resumeRequested: resumeRequestedRef.current,
    });

    const emitSyncSnapshot = useCallback(() => {
    if (!syncInspectorHandleRef.current) return;
    const snapshot = getSyncSnapshotRef.current();
    syncSnapshotRef.current = snapshot;
    syncInspectorHandleRef.current.publish(snapshot);
    }, []);

    const applySyncDebugSnapshot = useCallback(
    (snapshot: SyncDebugSnapshot) => {
    if (snapshot.state) {
    setState((prev) => ({
    ...prev,
    ...fromDebugSyncState(snapshot.state),
    }));
    }

    if (Array.isArray(snapshot.uniqueMediaIds)) {
    uniqueMediaIdsRef.current = [...snapshot.uniqueMediaIds];
    }

    if (typeof snapshot.pauseRequested === "boolean") {
    pauseRequestedRef.current = snapshot.pauseRequested;
    }

    if (typeof snapshot.resumeRequested === "boolean") {
    resumeRequestedRef.current = snapshot.resumeRequested;
    }

    if (snapshot.resumeSnapshot !== undefined) {
    resumeSnapshotRef.current = snapshot.resumeSnapshot
    ? {
    ...snapshot.resumeSnapshot,
    entries: cloneEntries(snapshot.resumeSnapshot.entries || []),
    }
    : null;
    initialEntriesRef.current = snapshot.resumeSnapshot
    ? cloneEntries(snapshot.resumeSnapshot.entries || [])
    : [];
    }

    syncSnapshotRef.current = getSyncSnapshotRef.current();
    emitSyncSnapshot();
    },
    [emitSyncSnapshot, setState],
    );

    useEffect(() => {
    emitSyncSnapshot();
    }, [state, emitSyncSnapshot]);

    useEffect(() => {
    if (!registerSyncStateInspector) return;

    syncSnapshotRef.current = getSyncSnapshotRef.current();

    const handle = registerSyncStateInspector<SyncDebugSnapshot>({
    id: "sync-state",
    label: "Synchronization",
    description:
    "AniList sync engine status, resume metadata, and control signals.",
    group: "Application",
    getSnapshot: () =>
    syncSnapshotRef.current ?? getSyncSnapshotRef.current(),
    setSnapshot: applySyncDebugSnapshot,
    });

    syncInspectorHandleRef.current = handle;

    return () => {
    handle.unregister();
    syncInspectorHandleRef.current = null;
    syncSnapshotRef.current = null;
    };
    }, [registerSyncStateInspector, applySyncDebugSnapshot]);

    const updateSnapshotFromProgress = (
    progress: SyncProgress | null,
    entriesForRun: AniListMediaEntry[],
    ) => {
    if (!progress) {
    resumeSnapshotRef.current = null;
    initialEntriesRef.current = [];
    uniqueMediaIdsRef.current = [];
    saveSnapshotToStorage(null);
    setState((prev) => ({
    ...prev,
    resumeAvailable: false,
    resumeMetadata: null,
    }));
    return;
    }

    const uniqueMediaIds = uniqueMediaIdsRef.current;

    if (!uniqueMediaIds.length) {
    resumeSnapshotRef.current = null;
    saveSnapshotToStorage(null);
    return;
    }

    const completedCount = Math.min(progress.completed, uniqueMediaIds.length);
    const completedMediaIds = uniqueMediaIds.slice(0, completedCount);
    const remainingMediaIds = uniqueMediaIds.slice(completedCount);

    if (
    remainingMediaIds.length === 0 &&
    (!progress.currentEntry || completedCount === uniqueMediaIds.length)
    ) {
    resumeSnapshotRef.current = null;
    initialEntriesRef.current = [];
    saveSnapshotToStorage(null);
    setState((prev) => ({
    ...prev,
    resumeAvailable: false,
    resumeMetadata: null,
    }));
    return;
    }

    const pendingEntries = entriesForRun.filter((entry) =>
    remainingMediaIds.includes(entry.mediaId),
    );

    if (progress.currentEntry) {
    const pendingIndex = pendingEntries.findIndex(
    (entry) => entry.mediaId === progress.currentEntry?.mediaId,
    );

    if (pendingIndex !== -1) {
    const metadata = pendingEntries[pendingIndex].syncMetadata;
    if (metadata?.useIncrementalSync && progress.currentStep) {
    pendingEntries[pendingIndex] = {
    ...pendingEntries[pendingIndex],
    syncMetadata: {
    ...metadata,
    resumeFromStep: progress.currentStep,
    },
    };
    }
    }
    }

    const snapshot: SyncResumeSnapshot = {
    entries: cloneEntries(pendingEntries),
    uniqueMediaIds: [...uniqueMediaIds],
    completedMediaIds,
    remainingMediaIds,
    progress: {
    ...progress,
    currentEntry: progress.currentEntry
    ? { ...progress.currentEntry }
    : null,
    },
    currentEntry: progress.currentEntry
    ? {
    mediaId: progress.currentEntry.mediaId,
    resumeFromStep: progress.currentStep ?? undefined,
    }
    : null,
    reportFragment: resumeSnapshotRef.current?.reportFragment ?? null,
    timestamp: Date.now(),
    };

    resumeSnapshotRef.current = snapshot;
    initialEntriesRef.current = cloneEntries(pendingEntries);
    // NOTE: Snapshot persistence deferred to batch completion callback (appendBatchResultToSnapshot)
    // to reduce redundant storage writes. Snapshot is updated in memory here but only persisted on batch boundary.
    setState((prev) => ({
    ...prev,
    resumeAvailable: true,
    resumeMetadata: {
    remainingMediaIds,
    timestamp: snapshot.timestamp,
    },
    }));

    emitSyncSnapshot();
    };

    /**
    * If automatic backups are enabled and this is a fresh sync, attempt to create one.
    * Errors are non-blocking and will be recorded to Sentry/breadcrumbs.
    */
    const performAutomaticBackupIfNeeded = async (isResume: boolean) => {
    if (isResume) return;

    // Verify Electron backup context is available
    if (!globalThis.electronBackup?.getScheduleConfig) {
    console.warn(
    "[Synchronization] ⚠️ Electron backup context not available - skipping automatic backup",
    );
    return;
    }

    // Get schedule config and check if automatic backup before sync is enabled
    const config = await globalThis.electronBackup.getScheduleConfig();
    if (!config.autoBackupBeforeSync) {
    return;
    }

    try {
    console.info(
    "[Synchronization] 📦 Creating automatic silent backup before sync...",
    );
    const result = await globalThis.electronBackup.createNow();

    if (!result.success) {
    throw new Error(result.error || "Failed to create backup");
    }

    console.info(
    `[Synchronization] ✅ Automatic backup created successfully: ${result.backupId}`,
    );
    Sentry.addBreadcrumb({
    category: "backup",
    message: "Automatic backup created before sync",
    level: "info",
    data: {
    backupId: result.backupId,
    },
    });
    } catch (backupError) {
    console.warn(
    "[Synchronization] ⚠️ Automatic backup failed (non-blocking):",
    backupError,
    );
    Sentry.addBreadcrumb({
    category: "backup",
    message: "Automatic backup failed before sync",
    level: "warning",
    data: {
    error:
    backupError instanceof Error
    ? backupError.message
    : String(backupError),
    },
    });
    }
    };

    /**
    * Records reading history snapshots after successful sync.
    * Captures current chapter progress for all synced manga.
    */
    const recordSyncHistory = () => {
    try {
    const matchResults = getSavedMatchResults();
    if (!matchResults || matchResults.length === 0) return;

    const now = Date.now();
    const historyEntries: ReadingHistoryEntry[] = [];

    for (const match of matchResults) {
    // Only record for matched/manual entries with chapter progress
    if (!["matched", "manual"].includes(match.status ?? "")) continue;
    if (!match.kenmeiManga?.chaptersRead) continue;
    if (match.kenmeiManga.chaptersRead <= 0) continue;

    // Prefer reading time from kenmeiManga.last_read_at if available
    let timestamp = now;
    if (match.kenmeiManga.lastReadAt) {
    const readTime = new Date(match.kenmeiManga.lastReadAt).getTime();
    if (!Number.isNaN(readTime)) {
    timestamp = readTime;
    }
    }

    historyEntries.push({
    timestamp,
    mangaId: match.kenmeiManga.id,
    title: match.kenmeiManga.title,
    chaptersRead: match.kenmeiManga.chaptersRead,
    status: match.kenmeiManga.status || "unknown",
    anilistId: match.selectedMatch?.id,
    });
    }

    if (historyEntries.length > 0) {
    recordReadingHistory(historyEntries);
    console.info(
    `[Synchronization] 📊 Recorded reading history: ${historyEntries.length} entries`,
    );
    }
    } catch (error) {
    console.warn(
    "[Synchronization] ⚠️ Failed to record reading history (non-blocking):",
    error,
    );
    }
    };

    /**
    * Initialize controller, ids, refs and initial progress state for a sync run.
    * @param entries - Array of AniList media entries to sync.
    * @param displayOrderMediaIds - Optional array of media IDs in display order.
    * @returns Object containing abort controller, unique media IDs, and initial progress state.
    * @source
    */
    const initializeSyncRun = (
    entries: AniListMediaEntry[],
    displayOrderMediaIds?: number[],
    ) => {
    const abortController = new AbortController();
    const uniqueMediaIds =
    displayOrderMediaIds && displayOrderMediaIds.length > 0
    ? displayOrderMediaIds
    : Array.from(new Set(entries.map((e) => e.mediaId)));

    uniqueMediaIdsRef.current = [...uniqueMediaIds];
    initialEntriesRef.current = cloneEntries(entries);

    const initialProgress: SyncProgress = {
    total: uniqueMediaIds.length,
    completed: 0,
    successful: 0,
    failed: 0,
    skipped: 0,
    currentEntry: null,
    currentStep: null,
    totalSteps: null,
    rateLimited: false,
    retryAfter: null,
    };

    setState((prev) => ({
    ...prev,
    isActive: true,
    error: null,
    abortController,
    progress: initialProgress,
    isPaused: false,
    resumeAvailable: false,
    resumeMetadata: null,
    }));

    updateSnapshotFromProgress(initialProgress, initialEntriesRef.current);
    saveSnapshotToStorage(resumeSnapshotRef.current);

    return { abortController, uniqueMediaIds, initialProgress };
    };

    /**
    * Run the core sync execution and return the resulting report and last progress.
    * @param entries - Array of AniList media entries to sync.
    * @param token - AniList authentication token.
    * @param abortController - Abort controller for cancellation.
    * @param uniqueMediaIds - Array of unique media IDs to sync.
    * @returns Sync execution result with report and final progress.
    * @source
    */
    const runSyncExecution = async (
    entries: AniListMediaEntry[],
    token: string,
    abortController: AbortController,
    uniqueMediaIds: number[],
    ) => {
    const executed = await executeSyncModeImpl(
    entries,
    token,
    abortController,
    {
    uniqueMediaIds,
    setState,
    updateSnapshotFromProgress,
    initialEntriesRef,
    resumeSnapshotRef,
    },
    );
    return executed;
    };

    const clearResumeSnapshot = () => {
    resumeSnapshotRef.current = null;
    initialEntriesRef.current = [];
    uniqueMediaIdsRef.current = [];
    saveSnapshotToStorage(null);
    setState((prev) => ({
    ...prev,
    resumeAvailable: false,
    resumeMetadata: null,
    }));

    emitSyncSnapshot();
    };

    // Load failed operations on mount
    useEffect(() => {
    setIsLoadingFailedOps(true);
    try {
    const queue = getFailedOperations();
    // Filter to only sync operations
    const syncOps = queue.operations.filter(
    (op) => op.type === "sync_update" || op.type === "sync_delete",
    );
    setFailedOperations(syncOps);
    console.debug(
    `[Synchronization] Loaded ${syncOps.length} failed operations`,
    );
    } catch (error) {
    console.error(
    "[Synchronization] Failed to load failed operations:",
    error,
    );
    } finally {
    setIsLoadingFailedOps(false);
    }
    }, []);

    /**
    * Helper function to refresh failed operations from storage.
    * Call after sync operations to pick up newly persisted failures.
    */
    const refreshFailedOperations = useCallback(() => {
    try {
    const queue = getFailedOperations();
    const syncOps = queue.operations.filter(
    (op) => op.type === "sync_update" || op.type === "sync_delete",
    );
    setFailedOperations(syncOps);
    console.debug(
    `[Synchronization] Refreshed failed operations: ${syncOps.length} total`,
    );
    } catch (error) {
    console.error(
    "[Synchronization] Failed to refresh failed operations:",
    error,
    );
    }
    }, []);

    useEffect(() => {
    if (hasLoadedSnapshotRef.current) return;
    hasLoadedSnapshotRef.current = true;

    const storedSnapshot = storage.getItem(STORAGE_KEYS.ACTIVE_SYNC_SNAPSHOT);
    if (!storedSnapshot) {
    console.debug("[Synchronization] 🔍 No stored sync snapshot found");
    return;
    }

    console.debug("[Synchronization] 🔍 Loading stored sync snapshot...");

    try {
    const parsed: SyncResumeSnapshot = JSON.parse(storedSnapshot);

    // Validate snapshot structure using centralized validation
    const validation = validateSyncSnapshot(parsed);
    if (!validation.valid) {
    console.warn(
    "[Synchronization] ⚠️ Snapshot validation failed: " +
    (validation.reason || "unknown reason"),
    );
    storage.removeItem(STORAGE_KEYS.ACTIVE_SYNC_SNAPSHOT);
    return;
    }

    // Check if snapshot is stale using centralized staleness check
    if (isSyncSnapshotStale(parsed.timestamp)) {
    console.warn(
    `[Synchronization] ⚠️ Snapshot is stale (${Math.round((Date.now() - parsed.timestamp) / (60 * 60 * 1000))} hours old), removing...`,
    );
    storage.removeItem(STORAGE_KEYS.ACTIVE_SYNC_SNAPSHOT);
    return;
    }

    console.info(
    `[Synchronization] ✅ Loaded sync snapshot: ${parsed.remainingMediaIds.length} remaining entries`,
    );

    resumeSnapshotRef.current = {
    ...parsed,
    progress: {
    ...parsed.progress,
    currentEntry: parsed.progress.currentEntry
    ? { ...parsed.progress.currentEntry }
    : null,
    },
    };
    initialEntriesRef.current = cloneEntries(parsed.entries || []);
    uniqueMediaIdsRef.current = [...parsed.uniqueMediaIds];

    setState((prev) => ({
    ...prev,
    progress: parsed.progress ?? prev.progress,
    isPaused: true,
    resumeAvailable: true,
    resumeMetadata: {
    remainingMediaIds: parsed.remainingMediaIds,
    timestamp: parsed.timestamp,
    },
    }));
    } catch (error) {
    console.error(
    "[Synchronization] ❌ Failed to load stored sync snapshot:",
    error,
    );
    storage.removeItem(STORAGE_KEYS.ACTIVE_SYNC_SNAPSHOT);
    }
    }, []);

    /**
    * Starts a new synchronization for the provided AniList media entries.
    * @param entries - AniList media entries to synchronize.
    * @param token - AniList authentication token.
    * @param _unused - Reserved for future use.
    * @param displayOrderMediaIds - Optional IDs to control sync order.
    * @returns Promise resolving when sync completes or fails.
    * @source
    */
    const startSync = useCallback(
    async (
    entries: AniListMediaEntry[],
    token: string,
    _unused?: undefined,
    displayOrderMediaIds?: number[],
    ) => {
    if (state.isActive) {
    console.warn("[Synchronization] ⚠️ Sync is already in progress");
    return;
    }
    if (!entries.length) {
    console.warn("[Synchronization] ⚠️ No entries to synchronize");
    setState((prev) => ({ ...prev, error: "No entries to synchronize" }));
    return;
    }
    if (!token) {
    console.error("[Synchronization] ❌ No authentication token available");
    setState((prev) => ({
    ...prev,
    error: "No authentication token available",
    }));
    return;
    }

    const isResume = resumeRequestedRef.current;
    resumeRequestedRef.current = false;

    console.info(
    `[Synchronization] ${isResume ? "▶️ Resuming" : "🚀 Starting"} sync for ${entries.length} entries`,
    );

    Sentry.addBreadcrumb({
    category: "sync",
    message: `Sync ${isResume ? "resumed" : "started"}`,
    level: "info",
    data: { entryCount: entries.length, isResume },
    });

    recordEvent({
    type: isResume ? "sync.resume" : "sync.start",
    message: `${isResume ? "Resumed" : "Started"} sync for ${entries.length} entries`,
    level: "info",
    metadata: { entryCount: entries.length, isResume },
    });

    if (!isResume && resumeSnapshotRef.current) {
    console.debug(
    "[Synchronization] 🔍 Clearing existing resume snapshot for fresh sync",
    );
    clearResumeSnapshot();
    }

    const existingReportFragment = isResume
    ? fromPersistedReport(resumeSnapshotRef.current?.reportFragment ?? null)
    : null;

    pauseRequestedRef.current = false;

    // Try to create a backup if configured (non-blocking)
    await performAutomaticBackupIfNeeded(isResume);

    // Main orchestration
    try {
    const { abortController, uniqueMediaIds } = initializeSyncRun(
    entries,
    displayOrderMediaIds,
    );

    const executed = await runSyncExecution(
    entries,
    token,
    abortController,
    uniqueMediaIds,
    );

    const syncReport = executed.syncReport;
    const lastReportedProgress = executed.lastReportedProgress;

    if (pauseRequestedRef.current) {
    console.info(
    "[Synchronization] ⏸️ Pausing sync and saving state for resume...",
    );
    Sentry.addBreadcrumb({
    category: "sync",
    message: "Sync paused by user",
    level: "info",
    data: { progress: lastReportedProgress },
    });
    handlePausedSync(
    existingReportFragment,
    syncReport,
    lastReportedProgress,
    resumeSnapshotRef,
    updateSnapshotFromProgress,
    initialEntriesRef,
    setState,
    );
    console.info("[Synchronization] ✅ Sync paused successfully");
    return;
    }

    console.debug("[Synchronization] 🔍 Finalizing sync operation...");
    finalizeSyncOperation(
    existingReportFragment,
    syncReport,
    pauseRequestedRef.current,
    clearResumeSnapshot,
    setState,
    );

    // Refresh failed operations state to reflect any newly persisted failures
    refreshFailedOperations();

    const finalReport = mergeReports(existingReportFragment, syncReport);

    // Record reading history snapshot after successful sync
    if (finalReport.successfulUpdates > 0) {
    recordSyncHistory();
    }

    Sentry.addBreadcrumb({
    category: "sync",
    message: "Sync completed",
    level: finalReport.failedUpdates > 0 ? "warning" : "info",
    data: {
    successfulUpdates: finalReport.successfulUpdates,
    failedUpdates: finalReport.failedUpdates,
    skippedEntries: finalReport.skippedEntries,
    totalEntries: finalReport.totalEntries,
    },
    });
    Sentry.setContext("sync", {
    totalEntries: finalReport.totalEntries,
    successfulUpdates: finalReport.successfulUpdates,
    failedUpdates: finalReport.failedUpdates,
    skippedEntries: finalReport.skippedEntries,
    });
    recordEvent({
    type: "sync.complete",
    message: `Sync completed: ${finalReport.successfulUpdates} success, ${finalReport.failedUpdates} failed`,
    level: finalReport.failedUpdates > 0 ? "warn" : "success",
    metadata: {
    totalEntries: finalReport.totalEntries,
    successfulUpdates: finalReport.successfulUpdates,
    failedUpdates: finalReport.failedUpdates,
    skippedEntries: finalReport.skippedEntries,
    },
    });
    } catch (error) {
    console.error("[Synchronization] Sync operation failed:", error);
    captureError(
    ErrorType.UNKNOWN,
    "Synchronization operation failed",
    error,
    {
    entryCount: entries.length,
    isResume,
    progress: state.progress,
    stage: "sync_execution",
    },
    );
    setState((prev) => ({
    ...prev,
    isActive: false,
    error: error instanceof Error ? error.message : String(error),
    abortController: null,
    isPaused: false,
    resumeAvailable: prev.resumeAvailable,
    }));
    }
    },
    [clearResumeSnapshot, state.isActive],
    );

    /**
    * Cancels the active synchronization, aborting all in-progress requests immediately.
    * Clears pending partial results and disables resume.
    * @source
    */
    const cancelSync = useCallback(() => {
    if (state.abortController) {
    console.info(
    "[Synchronization] Cancellation requested - aborting all sync operations",
    );
    recordEvent({
    type: "sync.cancel",
    message: "Sync cancelled by user",
    level: "warn",
    metadata: {
    progress: state.progress,
    },
    });
    state.abortController.abort();
    setState((prev) => ({
    ...prev,
    isActive: false,
    abortController: null,
    // Set a special error string for cancellation
    error: "Synchronization cancelled by user",
    // Preserve the current report if any (partial results)
    report: prev.report || null,
    isPaused: false,
    resumeAvailable: false,
    resumeMetadata: null,
    }));
    pauseRequestedRef.current = false;
    clearResumeSnapshot();

    // Add a message to make it clear the operation has been canceled
    console.info(
    "%c🛑 [Synchronization] SYNC CANCELLED - All operations stopped",
    "color: red; font-weight: bold",
    );
    }
    }, [clearResumeSnapshot, state.abortController]);

    const pauseSync = useCallback(() => {
    if (state.abortController) {
    console.info(
    "[Synchronization] ⏸️ Pause requested - stopping current sync after current task",
    );
    recordEvent({
    type: "sync.pause",
    message: "Sync paused by user",
    level: "info",
    metadata: {
    progress: state.progress,
    },
    });
    pauseRequestedRef.current = true;
    state.abortController.abort();
    emitSyncSnapshot();
    } else {
    console.warn(
    "[Synchronization] ⚠️ Cannot pause - no active sync operation",
    );
    }
    }, [state.abortController, emitSyncSnapshot]);

    /**
    * Resumes a previously paused synchronization with remaining entries.
    * Restores state from pause snapshot and continues processing.
    * @param entries - AniList media entries (used if snapshot entries unavailable).
    * @param token - AniList authentication token.
    * @param _unused - Reserved for future use.
    * @param displayOrderMediaIds - Optional IDs to override display order during resume.
    * @returns Promise resolving when resume completes or fails.
    * @source
    */
    const resumeSync = useCallback(
    async (
    entries: AniListMediaEntry[],
    token: string,
    _unused?: undefined,
    displayOrderMediaIds?: number[],
    ) => {
    const snapshot = resumeSnapshotRef.current;

    if (!snapshot) {
    console.warn(
    "[Synchronization] ⚠️ No paused synchronization state available to resume",
    );
    return;
    }

    const remainingIds = snapshot.remainingMediaIds;
    if (!remainingIds || remainingIds.length === 0) {
    console.warn(
    "[Synchronization] ⚠️ Paused state contains no remaining entries",
    );
    clearResumeSnapshot();
    return;
    }

    console.info(
    `[Synchronization] ▶️ Resuming sync with ${remainingIds.length} remaining entries`,
    );

    const sourceEntries =
    snapshot.entries && snapshot.entries.length > 0
    ? snapshot.entries
    : entries;

    const entriesToResume = cloneEntries(
    (sourceEntries.length > 0 ? sourceEntries : entries).filter((entry) =>
    remainingIds.includes(entry.mediaId),
    ),
    );

    if (!entriesToResume.length) {
    console.warn(
    "[Synchronization] ⚠️ No matching entries found to resume",
    );
    clearResumeSnapshot();
    return;
    }

    console.debug(
    `[Synchronization] 🔍 Prepared ${entriesToResume.length} entries for resume`,
    );

    resumeRequestedRef.current = true;
    emitSyncSnapshot();

    await startSync(
    entriesToResume,
    token,
    _unused,
    displayOrderMediaIds?.length ? displayOrderMediaIds : remainingIds,
    );
    },
    [clearResumeSnapshot, emitSyncSnapshot, startSync],
    );

    /**
    * Exports the error log from the last synchronization report.
    * If no report is available, this function does nothing.
    * @source
    */
    const exportErrors = useCallback(() => {
    if (state.report) {
    console.info("[Synchronization] 📤 Exporting error log...");
    exportSyncErrorLog(state.report);
    console.info("[Synchronization] ✅ Error log exported successfully");
    } else {
    console.warn("[Synchronization] ⚠️ No sync report available to export");
    }
    }, [state.report]);

    /**
    * Exports the complete synchronization report to a file.
    * If no report is available, this function does nothing.
    * @source
    */
    const exportReport = useCallback(() => {
    if (state.report) {
    console.info("[Synchronization] 📤 Exporting sync report...");
    exportSyncReport(state.report);
    console.info("[Synchronization] ✅ Sync report exported successfully");
    } else {
    console.warn("[Synchronization] ⚠️ No sync report available to export");
    }
    }, [state.report]);

    /**
    * Resets synchronization state to initial values, clearing all progress and reports.
    * @source
    */
    const reset = useCallback(() => {
    console.info("[Synchronization] 🔄 Resetting synchronization state...");
    clearResumeSnapshot();
    setState({
    isActive: false,
    progress: null,
    report: null,
    error: null,
    abortController: null,
    isPaused: false,
    resumeAvailable: false,
    resumeMetadata: null,
    });
    emitSyncSnapshot();
    }, [clearResumeSnapshot, emitSyncSnapshot]);

    // Retry a single failed operation
    const retryFailedOperation = useCallback(
    async (operationId: string): Promise<boolean> => {
    try {
    // Check if online before attempting retry
    if (!isOnline) {
    console.warn(
    "[Synchronization] Cannot retry operation: application is offline",
    );
    captureError(
    ErrorType.NETWORK,
    "Cannot retry: application is offline",
    new Error("Offline during retry attempt"),
    {
    context: "retryFailedOperation",
    operationId,
    },
    );
    return false;
    }

    // Validate token is available
    if (!authState?.accessToken) {
    console.error(
    "[Synchronization] Cannot retry operation: access token is missing or empty",
    );
    // Capture error for monitoring
    captureError(
    ErrorType.AUTH,
    "Cannot retry: access token unavailable",
    new Error("Cannot retry: access token unavailable"),
    {
    context: "retryFailedOperation",
    operationId,
    },
    );
    return false;
    }

    const operation = failedOperations.find((op) => op.id === operationId);
    if (!operation) {
    console.warn(
    `[Synchronization] Failed operation not found: ${operationId}`,
    );
    return false;
    }

    // Check if max retries exceeded
    if (operation.retryCount >= MAX_RETRY_ATTEMPTS) {
    console.warn(
    `[Synchronization] Max retries exceeded for operation: ${operationId}`,
    );
    return false;
    }

    // Extract entry data from payload
    const payload = operation.payload as Record<string, unknown>;

    // Validate and cast status to MediaListStatus
    const validStatuses: MediaListStatus[] = [
    "CURRENT",
    "PLANNING",
    "COMPLETED",
    "DROPPED",
    "PAUSED",
    "REPEATING",
    ];
    const statusString = (payload.status as string) || "";
    const status = validStatuses.includes(statusString as MediaListStatus)
    ? (statusString as MediaListStatus)
    : "PLANNING";

    const entry: AniListMediaEntry = {
    mediaId: (payload.mediaId as number) || 0,
    title: (payload.title as string) ?? "(Untitled)",
    status,
    progress: (payload.progress as number) || 0,
    score: (payload.score as number) || 0,
    private: (payload.private as boolean) ?? false,
    previousValues:
    (payload.previousValues as AniListMediaEntry["previousValues"]) ??
    null,
    syncMetadata:
    (payload.syncMetadata as AniListMediaEntry["syncMetadata"]) ?? null,
    };

    // Increment retry count in storage
    incrementRetryCount(operationId);

    // Acquire rate-limit slot to ensure proper spacing
    await acquireRateLimit();

    // Create single-entry array and call sync logic with token
    const batchResult = await syncMangaBatch(
    [entry],
    authState.accessToken,
    () => {},
    );

    if (batchResult.successfulUpdates > 0) {
    // Success - remove from failed operations
    removeFailedOperation(operationId);
    setFailedOperations((prev) =>
    prev.filter((op) => op.id !== operationId),
    );
    console.info(
    `[Synchronization] Successfully retried operation: ${operationId}`,
    );
    return true;
    } else {
    // Still failed - update in failed operations
    console.debug(
    `[Synchronization] Retry still failed for operation: ${operationId}`,
    );
    return false;
    }
    } catch (error) {
    console.error("[Synchronization] Error retrying operation:", error);
    return false;
    }
    },
    [failedOperations, authState, isOnline],
    );

    // Retry all failed operations
    const retryAllFailedOperations = useCallback(async (): Promise<number> => {
    // Check if online before attempting retry
    if (!isOnline) {
    console.warn(
    "[Synchronization] Cannot retry all operations: application is offline",
    );
    captureError(
    ErrorType.NETWORK,
    "Cannot retry all: application is offline",
    new Error("Offline during retry attempt"),
    {
    context: "retryAllFailedOperations",
    },
    );
    return 0;
    }

    // Validate token is available
    if (!authState?.accessToken) {
    console.error(
    "[Synchronization] Cannot retry all operations: access token is missing or empty",
    );
    captureError(
    ErrorType.AUTH,
    "Cannot retry all: access token unavailable",
    new Error("Cannot retry all: access token unavailable"),
    {
    context: "retryAllFailedOperations",
    },
    );
    return 0;
    }

    const results = {
    succeeded: 0,
    failed: 0,
    };

    for (const operation of failedOperations) {
    // Skip operations that have already exceeded max retries
    if (operation.retryCount >= MAX_RETRY_ATTEMPTS) {
    continue;
    }

    const success = await retryFailedOperation(operation.id);
    if (success) {
    results.succeeded += 1;
    } else {
    results.failed += 1;
    }
    }

    // Show summary toast
    if (results.succeeded > 0 || results.failed > 0) {
    console.info(
    `[Synchronization] Retry all complete: ${results.succeeded} succeeded, ${results.failed} failed`,
    );
    }

    return results.succeeded;
    }, [failedOperations, retryFailedOperation, isOnline, authState]);

    // Clear a failed operation
    const clearFailedOperation = useCallback((operationId: string): void => {
    removeFailedOperation(operationId);
    setFailedOperations((prev) => prev.filter((op) => op.id !== operationId));
    }, []);

    return [
    state,
    {
    startSync,
    cancelSync,
    pauseSync,
    resumeSync,
    exportErrors,
    exportReport,
    reset,
    failedOperations,
    isLoadingFailedOps,
    retryFailedOperation,
    retryAllFailedOperations,
    clearFailedOperation,
    },
    ];
    }