// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

part of '../../export_controller.dart';

/// Coordinates repository reads and export writer calls.
final class ExportController {
  /// Creates an export controller using [taskRepository].
  ExportController({
    required TaskRepository taskRepository,
    ExportWriterRegistry? writerRegistry,
  })  : _taskRepository = taskRepository,
        _writerRegistry = writerRegistry ?? ExportWriterRegistry.defaults();

  /// Private state stored as `_taskRepository` for this implementation.
  /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
  final TaskRepository _taskRepository;

  /// Private state stored as `_writerRegistry` for this implementation.
  /// The field is intentionally scoped to this library so only the owning type can change the related scheduler or UI behavior.
  final ExportWriterRegistry _writerRegistry;

  /// Create a writer for [format] and export owner-scoped tasks to [sink].
  Future<void> exportTasksToSink({
    required ExportContext context,
    required String format,
    required StringSink sink,
    int pageSize = 100,
  }) {
    core.logger.info(() => 'Task export to sink requested. '
        'ownerId=${context.ownerId.value} format=$format pageSize=$pageSize');
    final writer = _writerRegistry.create(format, sink);
    return exportTasks(
      context: context,
      writer: writer,
      pageSize: pageSize,
    );
  }

  /// Export all owner-scoped tasks through [writer].
  Future<void> exportTasks({
    required ExportContext context,
    required ExportWriter writer,
    int pageSize = 100,
  }) async {
    core.logger.info(() => 'Task export started. '
        'ownerId=${context.ownerId.value} timezone=${context.timezone} '
        'version=${context.version} pageSize=$pageSize');
    if (pageSize <= 0) {
      core.logger.warn(() => 'Task export rejected invalid page size. '
          'ownerId=${context.ownerId.value} pageSize=$pageSize');
      throw ArgumentError.value(pageSize, 'pageSize', 'Must be positive.');
    }

    await writer.begin(context);
    var pageCount = 0;
    var taskCount = 0;
    String? cursor;
    do {
      final result = await _taskRepository.findByOwner(
        ownerId: context.ownerId,
        page: core.PageRequest(cursor: cursor, limit: pageSize),
      );
      if (result.isLeft) {
        core.logger.warn(() => 'Task export repository read failed. '
            'ownerId=${context.ownerId.value} pageCount=$pageCount '
            'taskCount=$taskCount failureType=${result.left.runtimeType}');
        throw ExportRepositoryException(result.left);
      }
      final page = result.right;
      pageCount += 1;
      core.logger.finer(() => 'Task export page loaded. '
          'ownerId=${context.ownerId.value} pageNumber=$pageCount '
          'itemCount=${page.items.length} hasNext=${page.nextCursor != null}');
      for (final task in page.items) {
        await writer.writeTask(task);
        taskCount += 1;
      }
      cursor = page.nextCursor;
    } while (cursor != null);
    await writer.end();
    core.logger.info(() => 'Task export completed. '
        'ownerId=${context.ownerId.value} pageCount=$pageCount taskCount=$taskCount');
  }
}
