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

part of '../../document_migration.dart';

/// Private implementation type for `_LegacyMetadataInstants` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _LegacyMetadataInstants {
  /// Creates a `_LegacyMetadataInstants` instance with the values required by its invariants.
  /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
  const _LegacyMetadataInstants({
    required this.createdAt,
    required this.updatedAt,
  });

  /// Stores the `createdAt` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final String createdAt;

  /// Stores the `updatedAt` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final String updatedAt;
}

/// Private file-level value for `_taskTypeCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _taskTypeCodes = <String, String>{
  'flexible': 'flexible',
  'inflexible': 'inflexible',
  'critical': 'critical',
  'locked': 'locked',
  'surprise': 'surprise',
  'freeSlot': 'free_slot',
  'free_slot': 'free_slot',
};

/// Private file-level value for `_taskStatusCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _taskStatusCodes = <String, String>{
  'planned': 'planned',
  'active': 'active',
  'completed': 'completed',
  'missed': 'missed',
  'cancelled': 'cancelled',
  'noLongerRelevant': 'no_longer_relevant',
  'no_longer_relevant': 'no_longer_relevant',
  'backlog': 'backlog',
};

/// Private file-level value for `_priorityCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _priorityCodes = <String, String>{
  'veryLow': 'very_low',
  'very_low': 'very_low',
  'low': 'low',
  'medium': 'medium',
  'high': 'high',
  'veryHigh': 'very_high',
  'very_high': 'very_high',
};

/// Private file-level value for `_rewardCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _rewardCodes = <String, String>{
  'notSet': 'not_set',
  'not_set': 'not_set',
  'veryLow': 'very_low',
  'very_low': 'very_low',
  'low': 'low',
  'medium': 'medium',
  'high': 'high',
  'veryHigh': 'very_high',
  'very_high': 'very_high',
};

/// Private file-level value for `_difficultyCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _difficultyCodes = <String, String>{
  'notSet': 'not_set',
  'not_set': 'not_set',
  'veryEasy': 'very_easy',
  'very_easy': 'very_easy',
  'easy': 'easy',
  'medium': 'medium',
  'hard': 'hard',
  'veryHard': 'very_hard',
  'very_hard': 'very_hard',
};

/// Private file-level value for `_reminderProfileCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _reminderProfileCodes = <String, String>{
  'silent': 'silent',
  'gentle': 'gentle',
  'persistent': 'persistent',
  'strict': 'strict',
};

/// Private file-level value for `_backlogTagCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _backlogTagCodes = <String, String>{
  'wishlist': 'wishlist',
};

/// Private file-level value for `_lockedWeekdayCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _lockedWeekdayCodes = <String, String>{
  'monday': 'monday',
  'tuesday': 'tuesday',
  'wednesday': 'wednesday',
  'thursday': 'thursday',
  'friday': 'friday',
  'saturday': 'saturday',
  'sunday': 'sunday',
};

/// Private file-level value for `_lockedOverrideTypeCodes`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
const _lockedOverrideTypeCodes = <String, String>{
  'remove': 'remove',
  'replace': 'replace',
  'add': 'add',
};

/// Private file-level value for `_explicitOffsetPattern`.
/// Keeping this value near the helpers that use it avoids hidden global configuration while still preventing duplicate literals.
final _explicitOffsetPattern = RegExp(r'(Z|[+-]\d{2}:\d{2})$');

/// Top-level helper that performs the `_readSchemaVersion` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
_SchemaVersionRead _readSchemaVersion(Map<String, Object?> document) {
  if (!document.containsKey(DocumentFields.schemaVersion)) {
    return const _SchemaVersionRead.version(0);
  }
  final value = document[DocumentFields.schemaVersion];
  if (value is int) {
    return _SchemaVersionRead.version(value);
  }
  return const _SchemaVersionRead.failure('wrongType');
}

/// Top-level helper that performs the `_documentId` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _documentId(Map<String, Object?> document) {
  final value = document[DocumentFields.id];
  return value is String ? value : null;
}

/// Top-level helper that performs the `_failed` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
DocumentMigrationResult _failed({
  required DocumentMigrationEntity entity,
  required String? documentId,
  required int? fromSchemaVersion,
  required DocumentMigrationFailureCode failureCode,
  String? fieldName,
  String? detailCode,
}) {
  return DocumentMigrationResult(
    document: null,
    report: DocumentMigrationReport(
      entity: entity,
      status: DocumentMigrationStatus.failed,
      documentId: documentId,
      fromSchemaVersion: fromSchemaVersion,
      failureCode: failureCode,
      fieldName: fieldName,
      detailCode: detailCode,
    ),
  );
}

/// Top-level helper that performs the `_failedFromMapping` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
DocumentMigrationResult _failedFromMapping({
  required DocumentMigrationEntity entity,
  required String? documentId,
  required int fromSchemaVersion,
  required DocumentMigrationFailureCode failureCode,
  required DocumentMappingException error,
}) {
  return DocumentMigrationResult(
    document: null,
    report: DocumentMigrationReport(
      entity: entity,
      status: DocumentMigrationStatus.failed,
      documentId: documentId,
      fromSchemaVersion: fromSchemaVersion,
      failureCode: failureCode,
      mappingFailureCode: error.code,
      fieldName: error.fieldName,
      detailCode: error.detailCode,
    ),
  );
}

/// Top-level helper that performs the `_requiredString` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _requiredString(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value is String) {
    return value;
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredNullableString` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _requiredNullableString(
  Map<String, Object?> document,
  String fieldName,
) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value == null || value is String) {
    return value as String?;
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredNullableInt` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
int? _requiredNullableInt(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value == null || value is int) {
    return value as int?;
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredBool` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
bool _requiredBool(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value is bool) {
    return value;
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredMap` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Map<String, Object?> _requiredMap(
  Map<String, Object?> document,
  String fieldName,
) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value is Map) {
    return _deepCopyMap(value, fieldName);
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredLegacyCode` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _requiredLegacyCode(
  Map<String, Object?> document,
  String fieldName,
  Map<String, String> codes,
) {
  final raw = _requiredString(document, fieldName);
  final code = codes[raw];
  if (code == null) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'unknownCode:$raw',
    );
  }
  return code;
}

/// Top-level helper that performs the `_nullableLegacyCode` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _nullableLegacyCode(
  Map<String, Object?> document,
  String fieldName,
  Map<String, String> codes,
) {
  final raw = _requiredNullableString(document, fieldName);
  if (raw == null) {
    return null;
  }
  final code = codes[raw];
  if (code == null) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'unknownCode:$raw',
    );
  }
  return code;
}

/// Top-level helper that performs the `_requiredLegacyCodeList` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
List<String> _requiredLegacyCodeList(
  Map<String, Object?> document,
  String fieldName,
  Map<String, String> codes,
) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value is! List) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'wrongType',
    );
  }
  return value.map((entry) {
    if (entry is! String) {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'wrongType',
      );
    }
    final code = codes[entry];
    if (code == null) {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'unknownCode:$entry',
      );
    }
    return code;
  }).toList(growable: false);
}

/// Top-level helper that performs the `_requiredInstant` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _requiredInstant(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  final stored = _instantToStored(value, fieldName);
  if (stored == null) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'wrongType',
    );
  }
  return stored;
}

/// Top-level helper that performs the `_nullableInstant` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _nullableInstant(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  return _instantToStored(document[fieldName], fieldName);
}

/// Top-level helper that performs the `_optionalNullableInstant` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _optionalNullableInstant(
  Map<String, Object?> document,
  String fieldName,
) {
  if (!document.containsKey(fieldName)) {
    return null;
  }
  return _instantToStored(document[fieldName], fieldName);
}

/// Top-level helper that performs the `_instantToStored` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _instantToStored(Object? value, String fieldName) {
  if (value == null) {
    return null;
  }
  if (value is DateTime) {
    if (!value.isUtc) {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'ambiguousDateTime',
      );
    }
    return PersistenceDateTimeConvention.toStoredString(value);
  }
  if (value is String) {
    if (!_explicitOffsetPattern.hasMatch(value)) {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'ambiguousDateTime',
      );
    }
    try {
      return PersistenceDateTimeConvention.toStoredString(
        DateTime.parse(value),
      );
    } on FormatException {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'invalidDateTime',
      );
    }
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredCivilDate` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _requiredCivilDate(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = _civilDateToStored(document[fieldName], fieldName);
  if (value == null) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'wrongType',
    );
  }
  return value;
}

/// Top-level helper that performs the `_requiredNullableCivilDate` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _requiredNullableCivilDate(
  Map<String, Object?> document,
  String fieldName,
) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  return _civilDateToStored(document[fieldName], fieldName);
}

/// Top-level helper that performs the `_civilDateToStored` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _civilDateToStored(Object? value, String fieldName) {
  if (value == null) {
    return null;
  }
  if (value is String) {
    try {
      return PersistenceCivilDateConvention.toStoredString(
        PersistenceCivilDateConvention.fromStoredString(value),
      );
    } on Object {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'invalidCivilDate',
      );
    }
  }
  if (value is DateTime) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'ambiguousCivilDateTime',
    );
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_requiredWallTime` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _requiredWallTime(Map<String, Object?> document, String fieldName) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = _wallTimeToStored(document[fieldName], fieldName);
  if (value == null) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'wrongType',
    );
  }
  return value;
}

/// Top-level helper that performs the `_requiredNullableWallTime` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _requiredNullableWallTime(
  Map<String, Object?> document,
  String fieldName,
) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  return _wallTimeToStored(document[fieldName], fieldName);
}

/// Top-level helper that performs the `_wallTimeToStored` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _wallTimeToStored(Object? value, String fieldName) {
  if (value == null) {
    return null;
  }
  if (value is String) {
    try {
      return PersistenceWallTimeConvention.toStoredString(
        PersistenceWallTimeConvention.fromStoredString(value),
      );
    } on Object {
      throw _LegacyDocumentException(
        fieldName: fieldName,
        detailCode: 'invalidWallTime',
      );
    }
  }
  if (value is Map) {
    final map = _deepCopyMap(value, fieldName);
    final legacyValue = map[ClockTimeDocumentFields.value];
    if (legacyValue is String) {
      return _wallTimeToStored(legacyValue, fieldName);
    }
    final hour = map['hour'];
    final minute = map['minute'];
    if (hour is int && minute is int) {
      try {
        return WallTime(hour: hour, minute: minute).toIsoString();
      } on Object {
        throw _LegacyDocumentException(
          fieldName: fieldName,
          detailCode: 'invalidWallTime',
        );
      }
    }
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'wrongType',
  );
}

/// Top-level helper that performs the `_nullableRecurrence` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Map<String, Object?>? _nullableRecurrence(
  Map<String, Object?> document,
  String fieldName,
) {
  if (!document.containsKey(fieldName)) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'missingField',
    );
  }
  final value = document[fieldName];
  if (value == null) {
    return null;
  }
  if (value is! Map) {
    throw _LegacyDocumentException(
      fieldName: fieldName,
      detailCode: 'wrongType',
    );
  }
  final recurrence = _deepCopyMap(value, fieldName);
  final weekdays = recurrence[LockedBlockRecurrenceDocumentFields.weekdays];
  if (weekdays is! List) {
    throw _LegacyDocumentException(
      fieldName: LockedBlockRecurrenceDocumentFields.weekdays,
      detailCode: 'wrongType',
    );
  }
  return {
    LockedBlockRecurrenceDocumentFields.type:
        recurrence[LockedBlockRecurrenceDocumentFields.type] ?? 'weekly',
    LockedBlockRecurrenceDocumentFields.weekdays: weekdays.map((entry) {
      if (entry is! String) {
        throw const _LegacyDocumentException(
          fieldName: LockedBlockRecurrenceDocumentFields.weekdays,
          detailCode: 'wrongType',
        );
      }
      final code = _lockedWeekdayCodes[entry];
      if (code == null) {
        throw _LegacyDocumentException(
          fieldName: LockedBlockRecurrenceDocumentFields.weekdays,
          detailCode: 'unknownCode:$entry',
        );
      }
      return code;
    }).toList(growable: false),
  };
}

/// Top-level helper that performs the `_deepCopyDocument` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Map<String, Object?> _deepCopyDocument(Map<String, Object?> document) {
  return _deepCopyMap(document, 'document');
}

/// Top-level helper that performs the `_deepCopyMap` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Map<String, Object?> _deepCopyMap(Map<Object?, Object?> map, String fieldName) {
  return {
    for (final entry in map.entries)
      _stringKey(entry.key, fieldName): _deepCopyValue(entry.value, fieldName),
  };
}

/// Top-level helper that performs the `_stringKey` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _stringKey(Object? key, String fieldName) {
  if (key is String) {
    return key;
  }
  throw _LegacyDocumentException(
    fieldName: fieldName,
    detailCode: 'nonStringMapKey',
  );
}

/// Top-level helper that performs the `_deepCopyValue` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Object? _deepCopyValue(Object? value, String fieldName) {
  if (value is Map) {
    return _deepCopyMap(value, fieldName);
  }
  if (value is List) {
    return value.map((entry) => _deepCopyValue(entry, fieldName)).toList();
  }
  return value;
}
