import 'package:logging/logging.dart';

import 'api_client.dart';
import 'storage_service.dart';

/// Service for synchronizing annotations between local storage and server.
///
/// Handles downloading annotations on sheet open and uploading on save,
/// comparing timestamps to determine which version is newer.
class AnnotationSyncService {
  final _log = Logger('AnnotationSyncService');
  final ApiClient _apiClient;
  final StorageService _storageService;

  AnnotationSyncService({
    required ApiClient apiClient,
    required StorageService storageService,
  })  : _apiClient = apiClient,
        _storageService = storageService;

  /// Downloads annotations from server and merges with local storage.
  ///
  /// For each page, compares server's lastModified with local lastModified.
  /// If server is newer, overwrites local. Local annotations that are newer
  /// are preserved.
  Future<void> syncFromServer(String sheetUuid) async {
    try {
      _log.info('Syncing annotations from server for sheet $sheetUuid');

      // Fetch all annotations from server
      final serverAnnotations = await _apiClient.fetchAnnotations(sheetUuid);

      // Get all local annotations with metadata
      final localAnnotations =
          await _storageService.readAllAnnotationsWithMetadata(sheetUuid);

      int updatedCount = 0;

      // Process each server annotation
      for (final serverAnnotation in serverAnnotations) {
        final page = serverAnnotation.page;
        final localAnnotation = localAnnotations[page];

        bool shouldUpdate = false;

        if (localAnnotation == null) {
          // No local annotation - use server version
          shouldUpdate = true;
          _log.fine('Page $page: No local annotation, using server version');
        } else if (serverAnnotation.lastModified.isAfter(
          localAnnotation.lastModified,
        )) {
          // Server is newer - overwrite local
          shouldUpdate = true;
          _log.fine(
            'Page $page: Server is newer '
            '(server: ${serverAnnotation.lastModified}, '
            'local: ${localAnnotation.lastModified})',
          );
        } else {
          _log.fine(
            'Page $page: Local is newer or same, keeping local version',
          );
        }

        if (shouldUpdate) {
          await _storageService.writeAnnotationsWithMetadata(
            sheetUuid,
            page,
            serverAnnotation.annotationsJson,
            serverAnnotation.lastModified,
          );
          updatedCount++;
        }
      }

      _log.info(
        'Sync complete: $updatedCount pages updated from server '
        '(${serverAnnotations.length} total on server)',
      );
    } on ApiException catch (e) {
      _log.warning('Failed to sync annotations from server: $e');
    } catch (e) {
      _log.warning('Unexpected error syncing annotations: $e');
    }
  }

  /// Uploads a single page's annotation to the server.
  ///
  /// Called when annotations are saved (e.g., exiting paint mode).
  /// If upload fails (e.g., offline), the annotation is queued for later sync.
  Future<bool> uploadAnnotation({
    required String sheetUuid,
    required int page,
    required String annotationsJson,
    required DateTime lastModified,
  }) async {
    try {
      _log.info('Uploading annotation for sheet $sheetUuid page $page');

      await _apiClient.uploadAnnotation(
        sheetUuid: sheetUuid,
        page: page,
        lastModified: lastModified,
        annotationsJson: annotationsJson,
      );

      _log.info('Upload successful');
      return true;
    } on ApiException catch (e) {
      _log.warning('Failed to upload annotation, queuing for later: $e');
      await _queueForLaterUpload(
        sheetUuid: sheetUuid,
        page: page,
        annotationsJson: annotationsJson,
        lastModified: lastModified,
      );
      return false;
    } catch (e) {
      _log.warning(
          'Unexpected error uploading annotation, queuing for later: $e');
      await _queueForLaterUpload(
        sheetUuid: sheetUuid,
        page: page,
        annotationsJson: annotationsJson,
        lastModified: lastModified,
      );
      return false;
    }
  }

  /// Queues an annotation for later upload when connection is restored.
  Future<void> _queueForLaterUpload({
    required String sheetUuid,
    required int page,
    required String annotationsJson,
    required DateTime lastModified,
  }) async {
    await _storageService.writePendingAnnotationUpload(
      PendingAnnotationUpload(
        sheetUuid: sheetUuid,
        page: page,
        annotationsJson: annotationsJson,
        lastModified: lastModified,
      ),
    );
    _log.info('Annotation queued for later upload: $sheetUuid page $page');
  }
}
