import { FastingPlan } from '@/constants/Fasting'; import { FastingCycleNotificationManager } from '@/services/fastingCycleNotifications'; import { FastingCycle, FastingCycleSession } from '@/store/fastingSlice'; import { useCallback, useEffect, useRef, useState } from 'react'; export interface UseFastingCycleNotificationsState { isReady: boolean; isLoading: boolean; error: string | null; lastSyncTime: Date | null; } export interface UseFastingCycleNotificationsActions { verifyAndSync: () => Promise; forceSync: () => Promise; clearError: () => void; } export const useFastingCycleNotifications = ( cycle: FastingCycle | null, session: FastingCycleSession | null, plan: FastingPlan | undefined ): UseFastingCycleNotificationsState & UseFastingCycleNotificationsActions => { const [state, setState] = useState({ isReady: false, isLoading: true, error: null, lastSyncTime: null, }); const isInitializedRef = useRef(false); const isSyncingRef = useRef(false); // 初始化通知系统 const initialize = useCallback(async () => { if (isInitializedRef.current) return; try { setState(prev => ({ ...prev, isLoading: true, error: null })); // 周期性断食通知不需要额外的权限检查,因为它使用相同的通知系统 setState(prev => ({ ...prev, isReady: true, isLoading: false, })); isInitializedRef.current = true; } catch (error) { console.error('初始化周期性断食通知失败', error); setState(prev => ({ ...prev, isReady: false, isLoading: false, error: error instanceof Error ? error.message : '初始化失败', })); } }, []); // 验证和同步通知 const verifyAndSync = useCallback(async () => { if (!state.isReady || isSyncingRef.current) return; try { isSyncingRef.current = true; setState(prev => ({ ...prev, error: null })); if (cycle && session) { const isValid = await FastingCycleNotificationManager.verifyCycleNotifications(cycle, session); if (!isValid) { console.log('周期性断食通知需要重新同步'); try { await FastingCycleNotificationManager.scheduleCycleNotifications(cycle, session); } catch (syncError) { // 如果同步失败,记录错误但不阻止验证流程 console.error('重新安排通知失败', syncError); setState(prev => ({ ...prev, error: '重新安排通知失败:' + (syncError instanceof Error ? syncError.message : '未知错误'), })); return; } } } else { // 如果没有周期性计划,确保清理所有相关通知 await FastingCycleNotificationManager.cancelAllCycleNotifications(); } setState(prev => ({ ...prev, lastSyncTime: new Date(), })); } catch (error) { console.error('验证周期性断食通知失败', error); setState(prev => ({ ...prev, error: '同步周期性断食通知失败:' + (error instanceof Error ? error.message : '未知错误'), })); } finally { isSyncingRef.current = false; } }, [state.isReady, cycle, session]); // 强制同步通知 const forceSync = useCallback(async () => { if (!state.isReady) { console.warn('通知系统未就绪,无法强制同步'); return; } if (isSyncingRef.current) { console.warn('通知同步正在进行中,请稍后再试'); return; } try { isSyncingRef.current = true; setState(prev => ({ ...prev, error: null })); if (cycle && session) { await FastingCycleNotificationManager.scheduleCycleNotifications(cycle, session); console.log('周期性断食通知已强制同步', { cycle: cycle.planId, session: session.cycleDate, }); } else { await FastingCycleNotificationManager.cancelAllCycleNotifications(); } setState(prev => ({ ...prev, lastSyncTime: new Date(), })); } catch (error) { console.error('强制同步周期性断食通知失败', error); setState(prev => ({ ...prev, error: '强制同步周期性断食通知失败:' + (error instanceof Error ? error.message : '未知错误'), })); throw error; // 重新抛出错误以便调用方处理 } finally { isSyncingRef.current = false; } }, [state.isReady, cycle, session]); // 清除错误 const clearError = useCallback(() => { setState(prev => ({ ...prev, error: null })); }, []); // 初始化 useEffect(() => { initialize(); }, [initialize]); // 当周期性计划或会话变化时验证和同步 useEffect(() => { if (!state.isReady) return; // 使用防抖延迟执行,避免在快速状态变化时重复触发 const debounceTimer = setTimeout(() => { verifyAndSync(); }, 1000); // 1秒防抖 return () => clearTimeout(debounceTimer); }, [state.isReady, cycle?.planId, cycle?.enabled, session?.cycleDate, session?.startISO, session?.endISO]); return { ...state, verifyAndSync, forceSync, clearError, }; };