import { useCallback, useRef } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { downloadAsync, documentDirectory, makeDirectoryAsync } from 'expo-file-system/legacy'; import { fileStore } from '../services/fileStore'; import { apiClient } from '../api/client'; import { ENDPOINTS } from '../constants/api'; import { setIsSyncing } from './useSyncQueue'; const SYNC_DIR = `${documentDirectory}synced-files/`; export function usePullSync() { const queryClient = useQueryClient(); const isRunning = useRef(false); const pullNewFiles = useCallback(async () => { if (isRunning.current) return { pulled: 0 }; isRunning.current = true; try { setIsSyncing(true); let page = 1; const limit = 100; let total = 0; const backendResources: Array<{ id: string; name: string; mimeType: string; size: number; createdAt: string; url?: string; thumbnailUrl?: string; ownerId?: string; }> = []; do { const res = await apiClient.get<{ data: Array; meta?: { total: number } }>( `${ENDPOINTS.RESOURCES}?page=${page}&limit=${limit}&thumbnail=thumbnail_small`, ); backendResources.push(...(res.data ?? [])); total = res.meta?.total ?? res.data.length; page++; } while (backendResources.length < total); const registry = fileStore.getAllSynced(); const existingBackendIds = new Set( registry.filter((e) => e.backendId).map((e) => e.backendId) ); let pulled = 0; for (const br of backendResources) { if (existingBackendIds.has(br.id)) continue; if (br.size === 0) continue; try { const detail = await apiClient.get<{ url: string }>(`${ENDPOINTS.RESOURCES}/${br.id}`); const downloadUrl = detail.url; await makeDirectoryAsync(SYNC_DIR, { intermediates: true }); const safeName = br.name.replace(/[^a-zA-Z0-9._-]/g, '_'); const fileUri = `${SYNC_DIR}${br.id}_${safeName}`; const result = await downloadAsync(downloadUrl, fileUri); fileStore.upsert({ id: br.id, backendId: br.id, name: br.name, mimeType: br.mimeType, size: br.size, source: 'synced', localUri: result.uri, syncStatus: 'synced', parentResourceId: null, isFolder: 0, ocrText: null, thumbnailUrl: br.thumbnailUrl ?? null, ownerId: br.ownerId ?? null, createdAt: br.createdAt, updatedAt: br.createdAt, lastSyncedAt: new Date().toISOString(), }); pulled++; } catch { // skip individual file failures } } if (pulled > 0) { queryClient.invalidateQueries({ queryKey: ['resources'] }); } return { pulled }; } finally { setIsSyncing(false); isRunning.current = false; } }, [queryClient]); return { pullNewFiles }; }