import React, { useCallback, useMemo, useState } from 'react'; import { ActivityIndicator, SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, TouchableOpacity, useWindowDimensions, View, } from 'react-native'; import { NavigationProp, useFocusEffect, useNavigation } from '@react-navigation/native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { MaterialIcons } from '@expo/vector-icons'; import { RootStackParamList } from '../navigation/AppNavigator'; import { useTheme } from '../contexts/ThemeContext'; import CustomAlert from '../components/CustomAlert'; import { supabaseSyncService, SupabaseUser, RemoteSyncStats } from '../services/supabaseSyncService'; import { useAccount } from '../contexts/AccountContext'; import { useTraktContext } from '../contexts/TraktContext'; import { useSimklContext } from '../contexts/SimklContext'; import { useTranslation } from 'react-i18next'; const SyncSettingsScreen: React.FC = () => { const { currentTheme } = useTheme(); const { t } = useTranslation(); const { width } = useWindowDimensions(); const isTablet = width >= 768; const navigation = useNavigation>(); const insets = useSafeAreaInsets(); const { user, signOut } = useAccount(); const { isAuthenticated: traktAuthenticated } = useTraktContext(); const { isAuthenticated: simklAuthenticated } = useSimklContext(); const [loading, setLoading] = useState(false); const [syncCodeLoading, setSyncCodeLoading] = useState(false); const [sessionUser, setSessionUser] = useState(null); const [ownerId, setOwnerId] = useState(null); const [remoteStats, setRemoteStats] = useState(null); const [alertVisible, setAlertVisible] = useState(false); const [alertTitle, setAlertTitle] = useState(''); const [alertMessage, setAlertMessage] = useState(''); const [alertActions, setAlertActions] = useState void; style?: object }>>([]); const openAlert = useCallback( (title: string, message: string, actions?: Array<{ label: string; onPress: () => void; style?: object }>) => { setAlertTitle(title); setAlertMessage(message); setAlertActions(actions && actions.length > 0 ? actions : [{ label: 'OK', onPress: () => { } }]); setAlertVisible(true); }, [] ); const loadSyncState = useCallback(async () => { setLoading(true); try { await supabaseSyncService.initialize(); setSessionUser(supabaseSyncService.getCurrentSessionUser()); const owner = await supabaseSyncService.getEffectiveOwnerId(); setOwnerId(owner); const stats = await supabaseSyncService.getRemoteStats(); setRemoteStats(stats); } catch (error: any) { openAlert(t('common.error'), error?.message || t('settings.cloud_sync.auth.not_authenticated')); } finally { setLoading(false); } }, [openAlert]); useFocusEffect( useCallback(() => { loadSyncState(); }, [loadSyncState]) ); const authLabel = useMemo(() => { if (!supabaseSyncService.isConfigured()) return t('settings.cloud_sync.auth.not_configured'); if (!sessionUser) return t('settings.cloud_sync.auth.not_authenticated'); return `${t('settings.cloud_sync.auth.email_session')} ${sessionUser.email ? `(${sessionUser.email})` : ''}`; }, [sessionUser]); const statItems = useMemo(() => { if (!remoteStats) return []; return [ { label: t('settings.cloud_sync.stats.plugins'), value: remoteStats.plugins }, { label: t('settings.cloud_sync.stats.addons'), value: remoteStats.addons }, { label: t('settings.cloud_sync.stats.watch_progress'), value: remoteStats.watchProgress }, { label: t('settings.cloud_sync.stats.library_items'), value: remoteStats.libraryItems }, { label: t('settings.cloud_sync.stats.watched_items'), value: remoteStats.watchedItems }, ]; }, [remoteStats]); const isSignedIn = Boolean(user); const externalSyncServices = useMemo( () => [ traktAuthenticated ? 'Trakt' : null, simklAuthenticated ? 'Simkl' : null, ].filter(Boolean) as string[], [traktAuthenticated, simklAuthenticated] ); const externalSyncActive = externalSyncServices.length > 0; const handleManualSync = async () => { setSyncCodeLoading(true); try { await supabaseSyncService.pullAllToLocal(); openAlert(t('settings.cloud_sync.alerts.pull_success_title'), t('settings.cloud_sync.alerts.pull_success_msg')); await loadSyncState(); } catch (error: any) { openAlert(t('settings.cloud_sync.alerts.pull_failed_title'), error?.message || t('settings.cloud_sync.alerts.pull_failed_msg')); } finally { setSyncCodeLoading(false); } }; const handleUploadLocalData = async () => { setSyncCodeLoading(true); try { await supabaseSyncService.pushAllLocalData(); openAlert(t('settings.cloud_sync.alerts.push_success_title'), t('settings.cloud_sync.alerts.push_success_msg')); await loadSyncState(); } catch (error: any) { openAlert(t('settings.cloud_sync.alerts.push_failed_title'), error?.message || t('settings.cloud_sync.alerts.push_failed_msg')); } finally { setSyncCodeLoading(false); } }; const handleSignOut = async () => { setSyncCodeLoading(true); try { await signOut(); await loadSyncState(); } catch (error: any) { openAlert(t('settings.cloud_sync.alerts.sign_out_failed_title'), error?.message || t('settings.cloud_sync.alerts.sign_out_failed_msg')); } finally { setSyncCodeLoading(false); } }; return ( navigation.goBack()} style={styles.backButton}> {t('settings.title')} {t('settings.cloud_sync.title')} {loading ? ( ) : ( <> {t('settings.cloud_sync.hero_title')} {t('settings.cloud_sync.hero_subtitle')} {t('settings.cloud_sync.external_sync.title')} {externalSyncActive ? t('settings.cloud_sync.external_sync.active_msg', { services: externalSyncServices.join(' + ') }) : t('settings.cloud_sync.external_sync.inactive_msg')} {t('settings.cloud_sync.auth.account')} {user?.email ? t('settings.cloud_sync.auth.signed_in_as', { email: user.email }) : t('settings.cloud_sync.auth.not_signed_in') } {!isSignedIn ? ( navigation.navigate('Account')} > {t('settings.cloud_sync.actions.sign_in_up')} ) : ( <> navigation.navigate('AccountManage')} > {t('settings.cloud_sync.actions.manage_account')} {t('settings.cloud_sync.actions.sign_out')} )} {!isSignedIn ? ( {t('settings.cloud_sync.pre_auth.title')} {t('settings.cloud_sync.pre_auth.description')} {t('settings.cloud_sync.pre_auth.point_1')} {t('settings.cloud_sync.pre_auth.point_2')} {!supabaseSyncService.isConfigured() && ( {t('settings.cloud_sync.pre_auth.env_warning')} )} ) : ( <> {t('settings.cloud_sync.connection')} {authLabel} {t('settings.cloud_sync.auth.effective_owner', { id: ownerId || 'Unavailable' })} {!supabaseSyncService.isConfigured() && ( {t('settings.cloud_sync.pre_auth.env_warning')} )} {t('settings.cloud_sync.stats.title')} {!remoteStats ? ( {t('settings.cloud_sync.stats.signin_required')} ) : ( {statItems.map((item) => ( {item.value} {item.label} ))} )} {t('settings.cloud_sync.actions.title')} {t('settings.cloud_sync.actions.description')} {syncCodeLoading ? ( ) : ( {t('settings.cloud_sync.actions.pull_btn')} )} {t('settings.cloud_sync.actions.push_btn')} )} )} setAlertVisible(false)} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, loadingContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 16, paddingTop: 8, }, backButton: { flexDirection: 'row', alignItems: 'center', paddingVertical: 8, }, backText: { marginLeft: 8, fontSize: 16, fontWeight: '600', }, headerActions: { minWidth: 32, }, screenTitle: { fontSize: 32, fontWeight: '800', paddingHorizontal: 16, marginTop: 4, marginBottom: 10, }, content: { padding: 16, gap: 14, }, contentTablet: { alignSelf: 'center', width: '100%', maxWidth: 980, }, heroCard: { borderWidth: 1, borderRadius: 16, padding: 16, }, heroTopRow: { flexDirection: 'row', justifyContent: 'space-between', gap: 12, }, heroTitleWrap: { flex: 1, }, heroTitle: { fontSize: 20, fontWeight: '800', marginBottom: 4, }, heroSubtitle: { fontSize: 13, lineHeight: 18, }, card: { borderWidth: 1, borderRadius: 14, padding: 14, gap: 10, }, noteCard: { borderWidth: 1, borderRadius: 14, padding: 14, gap: 8, }, preAuthCard: { gap: 12, }, preAuthList: { gap: 6, marginTop: 2, }, preAuthItem: { fontSize: 13, lineHeight: 18, }, sectionHeader: { flexDirection: 'row', alignItems: 'center', gap: 8, }, cardTitle: { fontSize: 15, fontWeight: '700', }, cardText: { fontSize: 13, lineHeight: 18, }, warning: { fontSize: 12, marginTop: 4, }, statsGrid: { marginTop: 2, flexDirection: 'row', flexWrap: 'wrap', gap: 8, }, statTile: { width: '48%', borderWidth: 1, borderRadius: 10, paddingHorizontal: 10, paddingVertical: 8, }, statValue: { fontSize: 18, fontWeight: '800', marginBottom: 2, }, statLabel: { fontSize: 11, fontWeight: '600', }, buttonRow: { flexDirection: 'row', gap: 10, }, button: { flex: 1, borderRadius: 10, minHeight: 42, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 12, }, primaryButton: { borderWidth: 0, }, secondaryButton: { borderWidth: 1, }, buttonDisabled: { opacity: 0.55, }, buttonText: { color: '#fff', fontWeight: '700', fontSize: 13, }, }); export default SyncSettingsScreen;