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

part of '../../document_mapping.dart';

/// Document mapping for [Task].
abstract final class TaskDocumentMapping {
  /// Converts scheduler data for `toDocument` without changing the source object.
  /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details.
  static Map<String, Object?> toDocument(
    Task task, {
    required String ownerId,
    int revision = 1,
    bool clearSchedule = false,
    DateTime? backlogEnteredAt,
    String? backlogEnteredAtProvenance,
  }) {
    final scheduledStart = clearSchedule ? null : task.scheduledStart;
    final scheduledEnd = clearSchedule ? null : task.scheduledEnd;

    return {
      ..._commonFields(
        id: task.id,
        ownerId: ownerId,
        revision: revision,
        createdAt: task.createdAt,
        updatedAt: task.updatedAt,
      ),
      TaskDocumentFields.title: task.title,
      TaskDocumentFields.projectId: task.projectId,
      TaskDocumentFields.type: PersistenceEnumMapping.encodeTaskType(task.type),
      TaskDocumentFields.status:
          PersistenceEnumMapping.encodeTaskStatus(task.status),
      TaskDocumentFields.priority: task.priority == null
          ? null
          : PersistenceEnumMapping.encodePriority(task.priority!),
      TaskDocumentFields.reward:
          PersistenceEnumMapping.encodeReward(task.reward),
      TaskDocumentFields.difficulty:
          PersistenceEnumMapping.encodeDifficulty(task.difficulty),
      TaskDocumentFields.durationMinutes: task.durationMinutes,
      TaskDocumentFields.scheduledStart: _dateTimeToStored(scheduledStart),
      TaskDocumentFields.scheduledEnd: _dateTimeToStored(scheduledEnd),
      TaskDocumentFields.actualStart: _dateTimeToStored(task.actualStart),
      TaskDocumentFields.actualEnd: _dateTimeToStored(task.actualEnd),
      TaskDocumentFields.completedAt: _dateTimeToStored(task.completedAt),
      TaskDocumentFields.parentTaskId: task.parentTaskId,
      TaskDocumentFields.backlogTags: task.backlogTags
          .map(PersistenceEnumMapping.encodeBacklogTag)
          .toList(),
      TaskDocumentFields.reminderOverride: task.reminderOverride == null
          ? null
          : PersistenceEnumMapping.encodeReminderProfile(
              task.reminderOverride!),
      TaskDocumentFields.stats: TaskStatisticsDocumentMapping.toDocument(
        task.stats,
      ),
      TaskDocumentFields.backlogEnteredAt:
          _dateTimeToStored(backlogEnteredAt ?? task.backlogEnteredAt),
      TaskDocumentFields.backlogEnteredAtProvenance:
          backlogEnteredAtProvenance ?? task.backlogEnteredAtProvenance,
    };
  }

  /// Converts scheduler data for `fromDocument` without changing the source object.
  /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details.
  static Task fromDocument(Map<String, Object?> document) {
    return _mapInvalidValues(() {
      _readCommon(document);
      return Task(
        id: _requiredString(document, TaskDocumentFields.id),
        title: _requiredString(document, TaskDocumentFields.title),
        projectId: _requiredString(document, TaskDocumentFields.projectId),
        type: PersistenceEnumMapping.decodeTaskType(
          _requiredString(document, TaskDocumentFields.type),
        ),
        status: PersistenceEnumMapping.decodeTaskStatus(
          _requiredString(document, TaskDocumentFields.status),
        ),
        priority: PersistenceEnumMapping.decodeNullablePriority(
          _requiredNullableString(document, TaskDocumentFields.priority),
        ),
        reward: PersistenceEnumMapping.decodeReward(
          _requiredString(document, TaskDocumentFields.reward),
        ),
        difficulty: PersistenceEnumMapping.decodeDifficulty(
          _requiredString(document, TaskDocumentFields.difficulty),
        ),
        durationMinutes:
            _requiredNullableInt(document, TaskDocumentFields.durationMinutes),
        scheduledStart: _requiredNullableDateTime(
          document,
          TaskDocumentFields.scheduledStart,
        ),
        scheduledEnd: _requiredNullableDateTime(
          document,
          TaskDocumentFields.scheduledEnd,
        ),
        actualStart: _requiredNullableDateTime(
          document,
          TaskDocumentFields.actualStart,
        ),
        actualEnd: _requiredNullableDateTime(
          document,
          TaskDocumentFields.actualEnd,
        ),
        completedAt: _requiredNullableDateTime(
          document,
          TaskDocumentFields.completedAt,
        ),
        backlogEnteredAt: _requiredNullableDateTime(
          document,
          TaskDocumentFields.backlogEnteredAt,
        ),
        backlogEnteredAtProvenance: _requiredNullableString(
          document,
          TaskDocumentFields.backlogEnteredAtProvenance,
        ),
        parentTaskId: _requiredNullableString(
          document,
          TaskDocumentFields.parentTaskId,
        ),
        backlogTags: _backlogTagsFromDocument(document),
        reminderOverride: PersistenceEnumMapping.decodeNullableReminderProfile(
          _requiredNullableString(
            document,
            TaskDocumentFields.reminderOverride,
          ),
        ),
        createdAt: _requiredDateTime(document, TaskDocumentFields.createdAt),
        updatedAt: _requiredDateTime(document, TaskDocumentFields.updatedAt),
        stats: TaskStatisticsDocumentMapping.fromDocument(
          _requiredMap(document, TaskDocumentFields.stats),
        ),
      ).._validateTaskDocumentMetadata(document);
    });
  }

  /// Converts scheduler data for `_backlogTagsFromDocument` without changing the source object.
  /// Conversion helpers keep persistence and export shapes explicit so domain models do not depend on storage-specific details.
  static Set<BacklogTag> _backlogTagsFromDocument(
    Map<String, Object?> document,
  ) {
    final rawTags = _requiredList(document, TaskDocumentFields.backlogTags);
    return rawTags.map((tag) {
      if (tag is! String) {
        throw DocumentMappingException(
          code: DocumentMappingFailureCode.wrongType,
          fieldName: TaskDocumentFields.backlogTags,
        );
      }
      return PersistenceEnumMapping.decodeBacklogTag(tag);
    }).toSet();
  }
}
