import { useCallback, useEffect, useState } from 'react' import { nostrAuthService } from '@/lib/nostrAuth' import { MIN_EVENT_DATE } from '@/lib/platformConfig' import { objectCache } from '@/lib/objectCache' import { calculateDaysBetween, getCurrentTimestamp, getLastSyncDate, setLastSyncDate as setLastSyncDateStorage } from '@/lib/syncStorage' import { useSyncProgress } from '@/lib/hooks/useSyncProgress' import type { SyncProgress, SyncProgressBarController } from './types' type ConnectionState = { isInitialized: boolean; connected: boolean; pubkey: string | null } export function useSyncProgressBarController(): SyncProgressBarController | null { const connection = useNostrConnectionState() const [error, setError] = useState(null) const syncStatus = useSyncStatus() const { syncProgress, isSyncing, startMonitoring, stopMonitoring } = useSyncProgress({ onComplete: syncStatus.loadSyncStatus }) useAutoSyncEffect({ connection, isSyncing, loadSyncStatus: syncStatus.loadSyncStatus, startMonitoring, stopMonitoring, setError }) if (!connection.isInitialized || !connection.connected || !connection.pubkey) { return null } const progressPercentage = computeProgressPercentage(syncProgress) const isRecentlySynced = isRecentlySyncedFromLastSyncDate(syncStatus.lastSyncDate) const startDate = getSyncStartDate(syncStatus.lastSyncDate) const endDate = getCurrentTimestamp() return { error, dismissError: () => setError(null), isSyncing, syncProgress, progressPercentage, totalDays: syncStatus.totalDays, startDateLabel: formatSyncDate(startDate), endDateLabel: formatSyncDate(endDate), isRecentlySynced, onResyncClick: () => { void resynchronizeUserContent({ startMonitoring, stopMonitoring, loadSyncStatus: syncStatus.loadSyncStatus, setError }) }, } } function useNostrConnectionState(): ConnectionState { const initial = nostrAuthService.getState() const [state, setState] = useState<{ connected: boolean; pubkey: string | null }>(() => ({ connected: initial.connected ?? false, pubkey: initial.pubkey ?? null, })) const [isInitialized] = useState(true) useEffect(() => { const unsubscribe = nostrAuthService.subscribe((next) => setState({ connected: next.connected ?? false, pubkey: next.pubkey ?? null })) return () => unsubscribe() }, []) return { isInitialized, connected: state.connected, pubkey: state.pubkey } } function useSyncStatus(): { lastSyncDate: number | null; totalDays: number; loadSyncStatus: () => Promise } { const [lastSyncDate, setLastSyncDate] = useState(null) const [totalDays, setTotalDays] = useState(0) const loadSyncStatus = useCallback(async (): Promise => { try { const state = nostrAuthService.getState() if (!state.connected || !state.pubkey) { return } const storedLastSyncDate = await getLastSyncDate() const days = calculateDaysBetween(storedLastSyncDate, getCurrentTimestamp()) setLastSyncDate(storedLastSyncDate) setTotalDays(days) } catch (loadError) { console.error('[SyncProgressBar] Error loading sync status:', loadError) } }, []) return { lastSyncDate, totalDays, loadSyncStatus } } function useAutoSyncEffect(params: { connection: ConnectionState isSyncing: boolean loadSyncStatus: () => Promise startMonitoring: () => void stopMonitoring: () => void setError: (value: string | null) => void }): void { useEffect(() => { if (!params.connection.isInitialized || !params.connection.connected || !params.connection.pubkey) { return } void runAutoSyncCheck({ connection: { connected: true, pubkey: params.connection.pubkey }, isSyncing: params.isSyncing, loadSyncStatus: params.loadSyncStatus, startMonitoring: params.startMonitoring, stopMonitoring: params.stopMonitoring, setError: params.setError, }) }, [params.connection.connected, params.connection.isInitialized, params.connection.pubkey, params.isSyncing, params.loadSyncStatus, params.setError, params.startMonitoring, params.stopMonitoring]) } function formatSyncDate(timestamp: number): string { const date = new Date(timestamp * 1000) const locale = typeof window !== 'undefined' ? navigator.language : 'fr-FR' return date.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }) } function getSyncStartDate(lastSyncDate: number | null): number { return lastSyncDate ?? MIN_EVENT_DATE } function isRecentlySyncedFromLastSyncDate(lastSyncDate: number | null): boolean { return lastSyncDate !== null && lastSyncDate >= getCurrentTimestamp() - 3600 } async function resynchronizeUserContent(params: { startMonitoring: () => void stopMonitoring: () => void loadSyncStatus: () => Promise setError: (value: string | null) => void }): Promise { try { const state = nostrAuthService.getState() if (!state.connected || !state.pubkey) { return } await clearUserContentCache() await setLastSyncDateStorage(MIN_EVENT_DATE) await params.loadSyncStatus() await startUserSyncOrStop({ pubkey: state.pubkey, startMonitoring: params.startMonitoring, stopMonitoring: params.stopMonitoring }) } catch (resyncError) { console.error('[SyncProgressBar] Error resynchronizing:', resyncError) params.stopMonitoring() params.setError(resyncError instanceof Error ? resyncError.message : 'Erreur de synchronisation') } } async function clearUserContentCache(): Promise { await Promise.all([ objectCache.clear('author'), objectCache.clear('series'), objectCache.clear('publication'), objectCache.clear('review'), objectCache.clear('purchase'), objectCache.clear('sponsoring'), objectCache.clear('review_tip'), ]) } async function startUserSyncOrStop(params: { pubkey: string; startMonitoring: () => void; stopMonitoring: () => void }): Promise { const { swClient } = await import('@/lib/swClient') const isReady = await swClient.isReady() if (!isReady) { params.stopMonitoring() return } await swClient.startUserSync(params.pubkey) params.startMonitoring() } function computeProgressPercentage(syncProgress: SyncProgress): number { if (!syncProgress || syncProgress.totalSteps <= 0) { return 0 } return Math.min(100, (syncProgress.currentStep / syncProgress.totalSteps) * 100) } async function runAutoSyncCheck(params: { connection: { connected: boolean; pubkey: string | null } isSyncing: boolean loadSyncStatus: () => Promise startMonitoring: () => void stopMonitoring: () => void setError: (value: string | null) => void }): Promise { console.warn('[SyncProgressBar] Starting sync check...') await params.loadSyncStatus() const shouldStart = await shouldAutoStartSync({ isSyncing: params.isSyncing, pubkey: params.connection.pubkey }) if (!shouldStart || !params.connection.pubkey) { console.warn('[SyncProgressBar] Skipping auto-sync:', { shouldStart, isSyncing: params.isSyncing, hasPubkey: Boolean(params.connection.pubkey) }) return } console.warn('[SyncProgressBar] Starting auto-sync...') await startAutoSync({ pubkey: params.connection.pubkey, startMonitoring: params.startMonitoring, stopMonitoring: params.stopMonitoring, setError: params.setError, }) } async function shouldAutoStartSync(params: { isSyncing: boolean; pubkey: string | null }): Promise { if (params.isSyncing || !params.pubkey) { return false } const storedLastSyncDate = await getLastSyncDate() const currentTimestamp = getCurrentTimestamp() const isRecentlySynced = storedLastSyncDate >= currentTimestamp - 3600 console.warn('[SyncProgressBar] Sync status:', { storedLastSyncDate, currentTimestamp, isRecentlySynced }) return !isRecentlySynced } async function startAutoSync(params: { pubkey: string; startMonitoring: () => void; stopMonitoring: () => void; setError: (value: string | null) => void }): Promise { try { const { swClient } = await import('@/lib/swClient') const isReady = await swClient.isReady() if (!isReady) { params.stopMonitoring() return } await swClient.startUserSync(params.pubkey) params.startMonitoring() } catch (autoSyncError) { console.error('[SyncProgressBar] Error during auto-sync:', autoSyncError) params.stopMonitoring() params.setError(autoSyncError instanceof Error ? autoSyncError.message : 'Erreur de synchronisation') } }