// MongoDB-oriented persistence contract helpers.
//
// This file defines stable field names and encoding conventions that document
// codecs and future adapters should use. It deliberately does not serialize
// domain models or import a MongoDB client.

import 'time_contracts.dart';

/// V1 document-schema version.
const v1SchemaVersion = 1;

/// Stable V1 collection names for future MongoDB adapters.
abstract final class PersistenceCollections {
  static const tasks = 'tasks';
  static const projects = 'projects';
  static const projectStatistics = 'project_statistics';
  static const lockedBlocks = 'locked_blocks';
  static const lockedOverrides = 'locked_overrides';
  static const taskActivities = 'task_activities';
  static const ownerSettings = 'owner_settings';
  static const noticeAcknowledgements = 'notice_acknowledgements';
  static const applicationOperations = 'application_operations';
  static const schedulingSnapshots = 'scheduling_snapshots';

  static const authoritative = <String>{
    tasks,
    projects,
    projectStatistics,
    lockedBlocks,
    lockedOverrides,
    ownerSettings,
  };

  static const internalRetained = <String>{
    taskActivities,
    noticeAcknowledgements,
    applicationOperations,
    schedulingSnapshots,
  };
}

/// Sort direction in an adapter-neutral index specification.
enum PersistenceIndexDirection {
  ascending,
  descending,
}

/// One field in a declarative index key.
class PersistenceIndexField {
  const PersistenceIndexField(
    this.fieldName, {
    this.direction = PersistenceIndexDirection.ascending,
  });

  final String fieldName;
  final PersistenceIndexDirection direction;
}

/// A stable index plan future adapters can translate to driver-specific calls.
class PersistenceIndexSpec {
  const PersistenceIndexSpec({
    required this.name,
    required this.collection,
    required this.keys,
    this.unique = false,
    this.partialFilterFields = const <String>{},
    this.supportsQueries = const <String>{},
  });

  final String name;
  final String collection;
  final List<PersistenceIndexField> keys;
  final bool unique;
  final Set<String> partialFilterFields;
  final Set<String> supportsQueries;
}

/// Stable repository query identifiers for index coverage tests.
abstract final class RepositoryQueryNames {
  static const taskById = 'TaskRepository.findById';
  static const taskByOwner = 'TaskRepository.findByOwner';
  static const taskByStatus = 'TaskRepository.findByStatus';
  static const taskByProject = 'TaskRepository.findByProjectId';
  static const taskByParent = 'TaskRepository.findByParentTaskId';
  static const taskBacklogCandidates = 'TaskRepository.findBacklogCandidates';
  static const taskScheduledWindow =
      'TaskRepository.findScheduledInWindowForOwner';
  static const taskLocalDay = 'TaskRepository.findForLocalDay';
  static const projectByOwner = 'ProjectRepository.findByOwner';
  static const projectById = 'ProjectRepository.findById';
  static const lockedBlockByOwner = 'LockedBlockRepository.findBlocksByOwner';
  static const lockedBlockById = 'LockedBlockRepository.findBlockById';
  static const lockedOverrideByDate =
      'LockedBlockRepository.findOverridesForDate';
  static const taskActivityByOwner = 'TaskActivityRepository.findByOwner';
  static const taskActivityByOperation =
      'TaskActivityRepository.findByOperationId';
  static const taskActivityByTask = 'TaskActivityRepository.findByTaskId';
  static const taskActivityByProject = 'TaskActivityRepository.findByProjectId';
  static const projectStatisticsByProject =
      'ProjectStatisticsRepository.findByProjectId';
  static const ownerSettingsByOwner = 'OwnerSettingsRepository.findByOwnerId';
  static const noticeAcknowledgementByOwner =
      'NoticeAcknowledgementRepository.findByOwner';
  static const noticeAcknowledgementById =
      'NoticeAcknowledgementRepository.findById';
  static const operationByIdempotencyKey =
      'ApplicationOperationRepository.findByIdempotencyKey';
  static const schedulingSnapshotById = 'SchedulingSnapshotRepository.findById';
  static const schedulingSnapshotWindow =
      'SchedulingSnapshotRepository.findInWindow';
}

/// Required V1 index plan.
abstract final class PersistenceIndexCatalog {
  static const all = <PersistenceIndexSpec>[
    PersistenceIndexSpec(
      name: 'tasks_owner_id_unique',
      collection: PersistenceCollections.tasks,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.taskById,
        RepositoryQueryNames.taskByOwner,
      },
    ),
    PersistenceIndexSpec(
      name: 'tasks_owner_status_backlog_age',
      collection: PersistenceCollections.tasks,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskDocumentFields.status),
        PersistenceIndexField(TaskDocumentFields.backlogEnteredAt),
        PersistenceIndexField(TaskDocumentFields.createdAt),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.taskByStatus,
        RepositoryQueryNames.taskBacklogCandidates,
      },
    ),
    PersistenceIndexSpec(
      name: 'tasks_owner_scheduled_window',
      collection: PersistenceCollections.tasks,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskDocumentFields.scheduledStart),
        PersistenceIndexField(TaskDocumentFields.scheduledEnd),
        PersistenceIndexField(DocumentFields.id),
      ],
      partialFilterFields: {
        TaskDocumentFields.scheduledStart,
        TaskDocumentFields.scheduledEnd,
      },
      supportsQueries: {
        RepositoryQueryNames.taskScheduledWindow,
        RepositoryQueryNames.taskLocalDay,
      },
    ),
    PersistenceIndexSpec(
      name: 'tasks_owner_project_status',
      collection: PersistenceCollections.tasks,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskDocumentFields.projectId),
        PersistenceIndexField(TaskDocumentFields.status),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.taskByProject,
        RepositoryQueryNames.taskBacklogCandidates,
      },
    ),
    PersistenceIndexSpec(
      name: 'tasks_owner_parent_status',
      collection: PersistenceCollections.tasks,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskDocumentFields.parentTaskId),
        PersistenceIndexField(TaskDocumentFields.status),
        PersistenceIndexField(DocumentFields.id),
      ],
      partialFilterFields: {
        TaskDocumentFields.parentTaskId,
      },
      supportsQueries: {
        RepositoryQueryNames.taskByParent,
      },
    ),
    PersistenceIndexSpec(
      name: 'projects_owner_id_unique',
      collection: PersistenceCollections.projects,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.projectById,
      },
    ),
    PersistenceIndexSpec(
      name: 'projects_owner_archived_name',
      collection: PersistenceCollections.projects,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(ProjectDocumentFields.archivedAt),
        PersistenceIndexField(ProjectDocumentFields.name),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.projectByOwner,
      },
    ),
    PersistenceIndexSpec(
      name: 'project_stats_owner_project_unique',
      collection: PersistenceCollections.projectStatistics,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(ProjectStatisticsDocumentFields.projectId),
      ],
      supportsQueries: {
        RepositoryQueryNames.projectStatisticsByProject,
      },
    ),
    PersistenceIndexSpec(
      name: 'locked_blocks_owner_id_unique',
      collection: PersistenceCollections.lockedBlocks,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.lockedBlockById,
      },
    ),
    PersistenceIndexSpec(
      name: 'locked_blocks_owner_archived_name',
      collection: PersistenceCollections.lockedBlocks,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(LockedBlockDocumentFields.archivedAt),
        PersistenceIndexField(LockedBlockDocumentFields.name),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.lockedBlockByOwner,
      },
    ),
    PersistenceIndexSpec(
      name: 'locked_overrides_owner_id_unique',
      collection: PersistenceCollections.lockedOverrides,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
    ),
    PersistenceIndexSpec(
      name: 'locked_overrides_owner_date_block',
      collection: PersistenceCollections.lockedOverrides,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(LockedBlockOverrideDocumentFields.date),
        PersistenceIndexField(LockedBlockOverrideDocumentFields.lockedBlockId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.lockedOverrideByDate,
      },
    ),
    PersistenceIndexSpec(
      name: 'task_activities_owner_id_unique',
      collection: PersistenceCollections.taskActivities,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
    ),
    PersistenceIndexSpec(
      name: 'task_activities_owner_operation',
      collection: PersistenceCollections.taskActivities,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskActivityDocumentFields.operationId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.taskActivityByOperation,
      },
    ),
    PersistenceIndexSpec(
      name: 'task_activities_owner_task_time',
      collection: PersistenceCollections.taskActivities,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskActivityDocumentFields.taskId),
        PersistenceIndexField(TaskActivityDocumentFields.occurredAt),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.taskActivityByOwner,
        RepositoryQueryNames.taskActivityByTask,
      },
    ),
    PersistenceIndexSpec(
      name: 'task_activities_owner_project_code_time',
      collection: PersistenceCollections.taskActivities,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(TaskActivityDocumentFields.projectId),
        PersistenceIndexField(TaskActivityDocumentFields.code),
        PersistenceIndexField(TaskActivityDocumentFields.occurredAt),
      ],
      supportsQueries: {
        RepositoryQueryNames.taskActivityByProject,
      },
    ),
    PersistenceIndexSpec(
      name: 'owner_settings_owner_unique',
      collection: PersistenceCollections.ownerSettings,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.ownerSettingsByOwner,
      },
    ),
    PersistenceIndexSpec(
      name: 'notice_ack_owner_notice_unique',
      collection: PersistenceCollections.noticeAcknowledgements,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(NoticeAcknowledgementDocumentFields.noticeId),
      ],
      supportsQueries: {
        RepositoryQueryNames.noticeAcknowledgementById,
      },
    ),
    PersistenceIndexSpec(
      name: 'notice_ack_owner_acknowledged',
      collection: PersistenceCollections.noticeAcknowledgements,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(
          NoticeAcknowledgementDocumentFields.acknowledgedAt,
        ),
        PersistenceIndexField(NoticeAcknowledgementDocumentFields.noticeId),
      ],
      supportsQueries: {
        RepositoryQueryNames.noticeAcknowledgementByOwner,
      },
    ),
    PersistenceIndexSpec(
      name: 'operations_owner_operation_unique',
      collection: PersistenceCollections.applicationOperations,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(
          ApplicationOperationDocumentFields.operationId,
        ),
      ],
      supportsQueries: {
        RepositoryQueryNames.operationByIdempotencyKey,
      },
    ),
    PersistenceIndexSpec(
      name: 'snapshots_owner_id_unique',
      collection: PersistenceCollections.schedulingSnapshots,
      unique: true,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(DocumentFields.id),
      ],
      supportsQueries: {
        RepositoryQueryNames.schedulingSnapshotById,
      },
    ),
    PersistenceIndexSpec(
      name: 'snapshots_owner_dates_retention',
      collection: PersistenceCollections.schedulingSnapshots,
      keys: [
        PersistenceIndexField(DocumentFields.ownerId),
        PersistenceIndexField(SchedulingSnapshotDocumentFields.sourceDate),
        PersistenceIndexField(SchedulingSnapshotDocumentFields.targetDate),
        PersistenceIndexField(
          SchedulingSnapshotDocumentFields.retentionExpiresAt,
        ),
      ],
      supportsQueries: {
        RepositoryQueryNames.schedulingSnapshotWindow,
      },
    ),
  ];

  static Set<String> get supportedQueries {
    return {
      for (final spec in all) ...spec.supportsQueries,
    };
  }
}

/// Bounded payload and retention policy for non-authoritative documents.
abstract final class PersistencePayloadLimits {
  static const maxTaskActivityMetadataEntries = 50;
  static const maxSchedulingSnapshotTasks = 250;
  static const maxSchedulingSnapshotNotices = 100;
  static const maxSchedulingSnapshotChanges = 250;
  static const maxAppliedActivityIds = 1000;
  static const taskActivityRetention = Duration(days: 365);
  static const applicationOperationRetention = Duration(days: 90);
  static const schedulingSnapshotRetention = Duration(days: 30);
}

/// Guard result for bounded document payload checks.
class PersistenceGuardResult {
  const PersistenceGuardResult._({
    required this.isValid,
    this.fieldName,
    this.limit,
    this.actual,
  });

  factory PersistenceGuardResult.valid() {
    return const PersistenceGuardResult._(isValid: true);
  }

  factory PersistenceGuardResult.tooLarge({
    required String fieldName,
    required int limit,
    required int actual,
  }) {
    return PersistenceGuardResult._(
      isValid: false,
      fieldName: fieldName,
      limit: limit,
      actual: actual,
    );
  }

  final bool isValid;
  final String? fieldName;
  final int? limit;
  final int? actual;
}

/// Pure guard helpers for bounded embedded document payloads.
abstract final class PersistencePayloadGuard {
  static PersistenceGuardResult mapEntries({
    required String fieldName,
    required Map<Object?, Object?> value,
    required int limit,
  }) {
    if (value.length > limit) {
      return PersistenceGuardResult.tooLarge(
        fieldName: fieldName,
        limit: limit,
        actual: value.length,
      );
    }
    return PersistenceGuardResult.valid();
  }

  static PersistenceGuardResult listLength({
    required String fieldName,
    required Iterable<Object?> value,
    required int limit,
  }) {
    final actual = value.length;
    if (actual > limit) {
      return PersistenceGuardResult.tooLarge(
        fieldName: fieldName,
        limit: limit,
        actual: actual,
      );
    }
    return PersistenceGuardResult.valid();
  }
}

/// DateTime storage convention for future document persistence.
abstract final class PersistenceDateTimeConvention {
  /// Human-readable convention kept close to the helper for tests and docs.
  static const description =
      'Store DateTime values as UTC ISO-8601 strings and compare as UTC instants.';

  /// Convert a DateTime into the persisted string convention.
  static String toStoredString(DateTime value) {
    return value.toUtc().toIso8601String();
  }

  /// Parse a persisted DateTime string back into a UTC DateTime.
  static DateTime fromStoredString(String value) {
    return DateTime.parse(value).toUtc();
  }

  /// Compare two DateTime values by their UTC instant.
  static int compare(DateTime left, DateTime right) {
    return left.toUtc().compareTo(right.toUtc());
  }
}

/// Civil-date storage convention for future document persistence.
abstract final class PersistenceCivilDateConvention {
  /// Human-readable convention kept close to the helper for tests and docs.
  static const description =
      'Store CivilDate values as YYYY-MM-DD strings without timezone conversion.';

  /// Convert a CivilDate into the persisted string convention.
  static String toStoredString(CivilDate value) {
    return value.toIsoString();
  }

  /// Parse a persisted CivilDate string without applying a timezone.
  static CivilDate fromStoredString(String value) {
    return CivilDate.fromIsoString(value);
  }
}

/// Wall-time storage convention for future document persistence.
abstract final class PersistenceWallTimeConvention {
  /// Human-readable convention kept close to the helper for tests and docs.
  static const description =
      'Store WallTime values as HH:MM strings without date or timezone data.';

  /// Convert a WallTime into the persisted string convention.
  static String toStoredString(WallTime value) {
    return value.toIsoString();
  }

  /// Parse a persisted WallTime string without applying a date or timezone.
  static WallTime fromStoredString(String value) {
    return WallTime.fromIsoString(value);
  }
}

/// Legacy enum-name extension retained for older callers.
///
/// V1 codecs use explicit stable code maps in `document_mapping.dart` instead
/// of relying on this extension.
extension PersistenceEnumName on Enum {
  /// Legacy persisted name.
  String get persistenceName => name;
}

/// Shared MongoDB document field names.
abstract final class DocumentFields {
  /// MongoDB primary id field.
  static const id = '_id';

  /// Version of the document shape.
  static const schemaVersion = 'schemaVersion';

  /// Authorization-neutral owner scope.
  static const ownerId = 'ownerId';

  /// Optimistic-concurrency revision.
  static const revision = 'revision';

  /// Creation instant.
  static const createdAt = 'createdAt';

  /// Last update instant.
  static const updatedAt = 'updatedAt';

  static const common = <String>{
    schemaVersion,
    id,
    ownerId,
    revision,
    createdAt,
    updatedAt,
  };
}

/// Document field names for [Task] documents.
abstract final class TaskDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const title = 'title';
  static const projectId = 'projectId';
  static const type = 'type';
  static const status = 'status';
  static const priority = 'priority';
  static const reward = 'reward';
  static const difficulty = 'difficulty';
  static const durationMinutes = 'durationMinutes';
  static const scheduledStart = 'scheduledStart';
  static const scheduledEnd = 'scheduledEnd';
  static const actualStart = 'actualStart';
  static const actualEnd = 'actualEnd';
  static const completedAt = 'completedAt';
  static const parentTaskId = 'parentTaskId';
  static const backlogTags = 'backlogTags';
  static const reminderOverride = 'reminderOverride';
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const stats = 'stats';
  static const backlogEnteredAt = 'backlogEnteredAt';
  static const backlogEnteredAtProvenance = 'backlogEnteredAtProvenance';

  static const all = <String>{
    ...DocumentFields.common,
    title,
    projectId,
    type,
    status,
    priority,
    reward,
    difficulty,
    durationMinutes,
    scheduledStart,
    scheduledEnd,
    actualStart,
    actualEnd,
    completedAt,
    parentTaskId,
    backlogTags,
    reminderOverride,
    stats,
    backlogEnteredAt,
    backlogEnteredAtProvenance,
  };
}

/// Document field names for internal [TaskActivity] documents.
abstract final class TaskActivityDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const operationId = 'operationId';
  static const code = 'code';
  static const taskId = 'taskId';
  static const projectId = 'projectId';
  static const occurredAt = 'occurredAt';
  static const metadata = 'metadata';

  static const all = <String>{
    ...DocumentFields.common,
    operationId,
    code,
    taskId,
    projectId,
    occurredAt,
    metadata,
  };
}

/// Document field names for [TaskStatistics] embedded documents.
abstract final class TaskStatisticsDocumentFields {
  static const skippedDuringBurnoutCount = 'skippedDuringBurnoutCount';
  static const manuallyPushedCount = 'manuallyPushedCount';
  static const autoPushedCount = 'autoPushedCount';
  static const movedToBacklogCount = 'movedToBacklogCount';
  static const restoredFromBacklogCount = 'restoredFromBacklogCount';
  static const missedCount = 'missedCount';
  static const cancelledCount = 'cancelledCount';
  static const completedLateCount = 'completedLateCount';
  static const completedDuringLockedHoursCount =
      'completedDuringLockedHoursCount';
  static const completedDuringLockedHoursMinutes =
      'completedDuringLockedHoursMinutes';
  static const completedAfterShieldCount = 'completedAfterShieldCount';
  static const completedAfterPushCount = 'completedAfterPushCount';
  static const totalPushesBeforeCompletion = 'totalPushesBeforeCompletion';

  static const all = <String>{
    skippedDuringBurnoutCount,
    manuallyPushedCount,
    autoPushedCount,
    movedToBacklogCount,
    restoredFromBacklogCount,
    missedCount,
    cancelledCount,
    completedLateCount,
    completedDuringLockedHoursCount,
    completedDuringLockedHoursMinutes,
    completedAfterShieldCount,
    completedAfterPushCount,
    totalPushesBeforeCompletion,
  };
}

/// Document field names for [ProjectProfile] documents.
abstract final class ProjectDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const name = 'name';
  static const colorKey = 'colorKey';
  static const defaultPriority = 'defaultPriority';
  static const defaultReward = 'defaultReward';
  static const defaultDifficulty = 'defaultDifficulty';
  static const defaultReminderProfile = 'defaultReminderProfile';
  static const defaultDurationMinutes = 'defaultDurationMinutes';
  static const archivedAt = 'archivedAt';

  static const all = <String>{
    ...DocumentFields.common,
    name,
    colorKey,
    defaultPriority,
    defaultReward,
    defaultDifficulty,
    defaultReminderProfile,
    defaultDurationMinutes,
    archivedAt,
  };
}

/// Document field names for [ProjectStatistics] documents.
abstract final class ProjectStatisticsDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const projectId = 'projectId';
  static const completedTaskCount = 'completedTaskCount';
  static const durationMinuteCounts = 'durationMinuteCounts';
  static const completionTimeBucketCounts = 'completionTimeBucketCounts';
  static const totalPushesBeforeCompletion = 'totalPushesBeforeCompletion';
  static const completedAfterPushCount = 'completedAfterPushCount';
  static const rewardCounts = 'rewardCounts';
  static const difficultyCounts = 'difficultyCounts';
  static const reminderProfileCounts = 'reminderProfileCounts';
  static const appliedActivityIds = 'appliedActivityIds';

  static const all = <String>{
    ...DocumentFields.common,
    projectId,
    completedTaskCount,
    durationMinuteCounts,
    completionTimeBucketCounts,
    totalPushesBeforeCompletion,
    completedAfterPushCount,
    rewardCounts,
    difficultyCounts,
    reminderProfileCounts,
    appliedActivityIds,
  };
}

/// Document field names for [ClockTime] embedded documents.
abstract final class ClockTimeDocumentFields {
  static const value = 'value';

  static const all = <String>{
    value,
  };
}

/// Document field names for [LockedBlockRecurrence] embedded documents.
abstract final class LockedBlockRecurrenceDocumentFields {
  static const type = 'type';
  static const weekdays = 'weekdays';

  static const all = <String>{
    type,
    weekdays,
  };
}

/// Document field names for [LockedBlock] documents.
abstract final class LockedBlockDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const name = 'name';
  static const startTime = 'startTime';
  static const endTime = 'endTime';
  static const date = 'date';
  static const recurrence = 'recurrence';
  static const hiddenByDefault = 'hiddenByDefault';
  static const projectId = 'projectId';
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const archivedAt = 'archivedAt';

  static const all = <String>{
    ...DocumentFields.common,
    name,
    startTime,
    endTime,
    date,
    recurrence,
    hiddenByDefault,
    projectId,
    archivedAt,
  };
}

/// Document field names for [LockedBlockOverride] documents.
abstract final class LockedBlockOverrideDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const lockedBlockId = 'lockedBlockId';
  static const date = 'date';
  static const type = 'type';
  static const name = 'name';
  static const startTime = 'startTime';
  static const endTime = 'endTime';
  static const hiddenByDefault = 'hiddenByDefault';
  static const projectId = 'projectId';
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;

  static const all = <String>{
    ...DocumentFields.common,
    lockedBlockId,
    date,
    type,
    name,
    startTime,
    endTime,
    hiddenByDefault,
    projectId,
  };
}

/// Document field names for [OwnerSettings] documents.
abstract final class OwnerSettingsDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const timeZoneId = 'timeZoneId';
  static const dayStart = 'dayStart';
  static const dayEnd = 'dayEnd';
  static const compactModeEnabled = 'compactModeEnabled';
  static const backlogStaleness = 'backlogStaleness';

  static const all = <String>{
    ...DocumentFields.common,
    timeZoneId,
    dayStart,
    dayEnd,
    compactModeEnabled,
    backlogStaleness,
  };
}

/// Document field names for backlog staleness settings.
abstract final class BacklogStalenessDocumentFields {
  static const greenMaxAgeDays = 'greenMaxAgeDays';
  static const blueMaxAgeDays = 'blueMaxAgeDays';

  static const all = <String>{
    greenMaxAgeDays,
    blueMaxAgeDays,
  };
}

/// Document field names for notice acknowledgement documents.
abstract final class NoticeAcknowledgementDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const noticeId = 'noticeId';
  static const acknowledgedAt = 'acknowledgedAt';

  static const all = <String>{
    ...DocumentFields.common,
    noticeId,
    acknowledgedAt,
  };
}

/// Document field names for idempotent operation records.
abstract final class ApplicationOperationDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const operationId = 'operationId';
  static const operationName = 'operationName';
  static const committedAt = 'committedAt';

  static const all = <String>{
    ...DocumentFields.common,
    operationId,
    operationName,
    committedAt,
  };
}

/// Document field names for [SchedulingStateSnapshot] documents.
abstract final class SchedulingSnapshotDocumentFields {
  static const schemaVersion = DocumentFields.schemaVersion;
  static const id = DocumentFields.id;
  static const ownerId = DocumentFields.ownerId;
  static const revision = DocumentFields.revision;
  static const createdAt = DocumentFields.createdAt;
  static const updatedAt = DocumentFields.updatedAt;
  static const capturedAt = 'capturedAt';
  static const sourceDate = 'sourceDate';
  static const targetDate = 'targetDate';
  static const window = 'window';
  static const tasks = 'tasks';
  static const lockedIntervals = 'lockedIntervals';
  static const requiredVisibleIntervals = 'requiredVisibleIntervals';
  static const notices = 'notices';
  static const changes = 'changes';
  static const overlaps = 'overlaps';
  static const operationName = 'operationName';
  static const retentionExpiresAt = 'retentionExpiresAt';
  static const truncated = 'truncated';

  static const all = <String>{
    ...DocumentFields.common,
    capturedAt,
    sourceDate,
    targetDate,
    window,
    tasks,
    lockedIntervals,
    requiredVisibleIntervals,
    notices,
    changes,
    overlaps,
    operationName,
    retentionExpiresAt,
    truncated,
  };
}

/// Document field names for [SchedulingWindow] embedded documents.
abstract final class SchedulingWindowDocumentFields {
  static const start = 'start';
  static const end = 'end';

  static const all = <String>{
    start,
    end,
  };
}

/// Document field names for [TimeInterval] embedded documents.
abstract final class TimeIntervalDocumentFields {
  static const start = 'start';
  static const end = 'end';
  static const label = 'label';

  static const all = <String>{
    start,
    end,
    label,
  };
}

/// Document field names for [SchedulingNotice] embedded documents.
abstract final class SchedulingNoticeDocumentFields {
  static const message = 'message';
  static const type = 'type';
  static const taskId = 'taskId';
  static const issueCode = 'issueCode';
  static const movementCode = 'movementCode';
  static const conflictCode = 'conflictCode';
  static const parameters = 'parameters';

  static const all = <String>{
    message,
    type,
    taskId,
    issueCode,
    movementCode,
    conflictCode,
    parameters,
  };
}

/// Document field names for [SchedulingChange] embedded documents.
abstract final class SchedulingChangeDocumentFields {
  static const taskId = 'taskId';
  static const previousStart = 'previousStart';
  static const previousEnd = 'previousEnd';
  static const nextStart = 'nextStart';
  static const nextEnd = 'nextEnd';

  static const all = <String>{
    taskId,
    previousStart,
    previousEnd,
    nextStart,
    nextEnd,
  };
}

/// Document field names for [SchedulingOverlap] embedded documents.
abstract final class SchedulingOverlapDocumentFields {
  static const taskId = 'taskId';
  static const taskInterval = 'taskInterval';
  static const blockedInterval = 'blockedInterval';

  static const all = <String>{
    taskId,
    taskInterval,
    blockedInterval,
  };
}

/// Every field-name set currently committed for future document mapping.
abstract final class PersistenceDocumentFieldSets {
  static const all = <Set<String>>[
    DocumentFields.common,
    TaskDocumentFields.all,
    TaskActivityDocumentFields.all,
    TaskStatisticsDocumentFields.all,
    ProjectDocumentFields.all,
    ProjectStatisticsDocumentFields.all,
    ClockTimeDocumentFields.all,
    LockedBlockRecurrenceDocumentFields.all,
    LockedBlockDocumentFields.all,
    LockedBlockOverrideDocumentFields.all,
    OwnerSettingsDocumentFields.all,
    BacklogStalenessDocumentFields.all,
    NoticeAcknowledgementDocumentFields.all,
    ApplicationOperationDocumentFields.all,
    SchedulingSnapshotDocumentFields.all,
    SchedulingWindowDocumentFields.all,
    TimeIntervalDocumentFields.all,
    SchedulingNoticeDocumentFields.all,
    SchedulingChangeDocumentFields.all,
    SchedulingOverlapDocumentFields.all,
  ];
}
