sync method

Future<void> sync()

Synchronizes the local and remote data.

Implementation

Future<void> sync() async {
  if (_isSyncing) {
    _logger.d('SyncService: Sync already in progress, skipping...');
    return; // Exit if another sync is running
  }
  _isSyncing = true; // Set the flag to indicate sync is starting

  try {
    _logger.d('SyncService: Starting sync process...');

    // 1. Ensure all media files are uploaded
    _logger.d('SyncService: Uploading local files...');
    await _uploadLocalFiles();
    _logger.d('SyncService: Local files uploaded successfully.');

    // 2. Get sync timestamps
    _logger.d('SyncService: Getting last sync time...');
    final lastSyncTime = await localRepository.getLastSyncServerTime();
    _logger.d('SyncService: Last sync time: $lastSyncTime');

    _logger.d('SyncService: Getting latest server sync time...');
    final serverTime = await remoteRepository.getLatestServerSyncTime();
    _logger.d('SyncService: Latest server sync time: $serverTime');

    // 3. Fetch items from remote (if needed)
    var itemsToFetch = <T>[];
    if (serverTime != null) {
      _logger.d('SyncService: Fetching items from remote...');
      itemsToFetch =
          await remoteRepository.fetchItemsByServerWrittenTimeRange(
        from: lastSyncTime,
        to: serverTime,
      );
      _logger.d(
        'SyncService: Fetched ${itemsToFetch.length} items from remote.',
      );
    }

    // 4. Filter fetched items (LWW conflict resolution)
    _logger.d('SyncService: Filtering fetched items...');
    final filteredFetchedItems = await _filterFetchedItems(itemsToFetch);
    _logger.d(
      'SyncService: ${filteredFetchedItems.length} items remain after LWW',
    );

    // 5. Update local repository
    _logger.d('SyncService: Updating local repository...');
    await localRepository.addOrUpdate(filteredFetchedItems, fromCloud: true);
    _logger.d('SyncService: Local repository updated.');

    // 6. Download missing files (NEW - Add this step)
    _logger.d('SyncService: Downloading missing files...');
    await _downloadMissingFiles();
    _logger.d('SyncService: Missing files downloaded successfully.');

    // 7. Get unsynced items after conflict resolution
    _logger.d('SyncService: Getting unsynced items...');
    final itemsToPush = await localRepository.getUnsyncedItems();
    _logger.d('SyncService: Found ${itemsToPush.length} unsynced items.');

    // 8. Push to remote
    if (itemsToPush.isNotEmpty) {
      _logger.d('SyncService: Pushing unsynced items to remote...');
      await remoteRepository.pushUnsyncedItems(itemsToPush);
      _logger.d('SyncService: Unsynced items pushed successfully.');
    } else {
      _logger.d('SyncService: No unsynced items to push.');
    }

    // 9. Manually mark pushed items as synced (without triggering updatedAt)
    for (final item in itemsToPush) {
      final updatedItem = item.copyWith(
        serverTimeSyncedAt: serverTime,
        localTimeSyncedAt: DateTime.now(),
      ) as T;
      _logger.d('SyncService: Marking item ${item.id} as synced...');
      await localRepository.update(updatedItem);
      _logger.d('SyncService: Item ${item.id} marked as synced.');
    }

    _logger.d('SyncService: Sync process completed.');
  } catch (e) {
    _logger.e('SyncService: Error during sync: $e');
    rethrow;
  } finally {
    _isSyncing = false; // Reset the flag after sync is done
  }
}