import 'dart:convert'; /// Represents the daily record for a specific calendar date in the Word of the Day practice. /// Supports both Single Word Mode (1 resonant archetype) and Triptych Mode (Morning, Day, Evening). class WordOfDayRecord { final String dateKey; // 'yyyy-MM-dd' final int wordId; // base id for Single Word Mode final bool isRevealed; // whether Single Word is revealed final bool isStepCompleted; // whether Single Word step is checked off final String diaryNote; // user reflection on daily synchronicity final DateTime? revealedAt; final DateTime? completedAt; // Triptych fields (3 words: Morning, Day, Evening) final bool isTriptychMode; final int morningWordId; final int dayWordId; final int eveningWordId; final bool isMorningRevealed; final bool isDayRevealed; final bool isEveningRevealed; final bool isDayStepCompleted; final DateTime? morningRevealedAt; final DateTime? dayRevealedAt; final DateTime? eveningRevealedAt; const WordOfDayRecord({ required this.dateKey, required this.wordId, this.isRevealed = false, this.isStepCompleted = false, this.diaryNote = '', this.revealedAt, this.completedAt, this.isTriptychMode = false, this.morningWordId = 0, this.dayWordId = 0, this.eveningWordId = 0, this.isMorningRevealed = false, this.isDayRevealed = false, this.isEveningRevealed = false, this.isDayStepCompleted = false, this.morningRevealedAt, this.dayRevealedAt, this.eveningRevealedAt, }); bool get isAnyRevealed => isRevealed || isMorningRevealed || isDayRevealed || isEveningRevealed; bool get areAllTriptychRevealed => isMorningRevealed && isDayRevealed && isEveningRevealed; bool get isAnyStepCompleted => isStepCompleted || isDayStepCompleted; WordOfDayRecord copyWith({ String? dateKey, int? wordId, bool? isRevealed, bool? isStepCompleted, String? diaryNote, DateTime? revealedAt, DateTime? completedAt, bool? isTriptychMode, int? morningWordId, int? dayWordId, int? eveningWordId, bool? isMorningRevealed, bool? isDayRevealed, bool? isEveningRevealed, bool? isDayStepCompleted, DateTime? morningRevealedAt, DateTime? dayRevealedAt, DateTime? eveningRevealedAt, }) { return WordOfDayRecord( dateKey: dateKey ?? this.dateKey, wordId: wordId ?? this.wordId, isRevealed: isRevealed ?? this.isRevealed, isStepCompleted: isStepCompleted ?? this.isStepCompleted, diaryNote: diaryNote ?? this.diaryNote, revealedAt: revealedAt ?? this.revealedAt, completedAt: completedAt ?? this.completedAt, isTriptychMode: isTriptychMode ?? this.isTriptychMode, morningWordId: morningWordId ?? this.morningWordId, dayWordId: dayWordId ?? this.dayWordId, eveningWordId: eveningWordId ?? this.eveningWordId, isMorningRevealed: isMorningRevealed ?? this.isMorningRevealed, isDayRevealed: isDayRevealed ?? this.isDayRevealed, isEveningRevealed: isEveningRevealed ?? this.isEveningRevealed, isDayStepCompleted: isDayStepCompleted ?? this.isDayStepCompleted, morningRevealedAt: morningRevealedAt ?? this.morningRevealedAt, dayRevealedAt: dayRevealedAt ?? this.dayRevealedAt, eveningRevealedAt: eveningRevealedAt ?? this.eveningRevealedAt, ); } Map toMap() => { 'dateKey': dateKey, 'wordId': wordId, 'isRevealed': isRevealed, 'isStepCompleted': isStepCompleted, 'diaryNote': diaryNote, if (revealedAt != null) 'revealedAt': revealedAt!.toIso8601String(), if (completedAt != null) 'completedAt': completedAt!.toIso8601String(), 'isTriptychMode': isTriptychMode, 'morningWordId': morningWordId, 'dayWordId': dayWordId, 'eveningWordId': eveningWordId, 'isMorningRevealed': isMorningRevealed, 'isDayRevealed': isDayRevealed, 'isEveningRevealed': isEveningRevealed, 'isDayStepCompleted': isDayStepCompleted, if (morningRevealedAt != null) 'morningRevealedAt': morningRevealedAt!.toIso8601String(), if (dayRevealedAt != null) 'dayRevealedAt': dayRevealedAt!.toIso8601String(), if (eveningRevealedAt != null) 'eveningRevealedAt': eveningRevealedAt!.toIso8601String(), }; factory WordOfDayRecord.fromMap(Map map) => WordOfDayRecord( dateKey: map['dateKey'] as String? ?? '', wordId: (map['wordId'] as num?)?.toInt() ?? 0, isRevealed: map['isRevealed'] as bool? ?? false, isStepCompleted: map['isStepCompleted'] as bool? ?? false, diaryNote: map['diaryNote'] as String? ?? '', revealedAt: map['revealedAt'] != null ? DateTime.tryParse(map['revealedAt'] as String) : null, completedAt: map['completedAt'] != null ? DateTime.tryParse(map['completedAt'] as String) : null, isTriptychMode: map['isTriptychMode'] as bool? ?? false, morningWordId: (map['morningWordId'] as num?)?.toInt() ?? 0, dayWordId: (map['dayWordId'] as num?)?.toInt() ?? 0, eveningWordId: (map['eveningWordId'] as num?)?.toInt() ?? 0, isMorningRevealed: map['isMorningRevealed'] as bool? ?? false, isDayRevealed: map['isDayRevealed'] as bool? ?? false, isEveningRevealed: map['isEveningRevealed'] as bool? ?? false, isDayStepCompleted: map['isDayStepCompleted'] as bool? ?? false, morningRevealedAt: map['morningRevealedAt'] != null ? DateTime.tryParse(map['morningRevealedAt'] as String) : null, dayRevealedAt: map['dayRevealedAt'] != null ? DateTime.tryParse(map['dayRevealedAt'] as String) : null, eveningRevealedAt: map['eveningRevealedAt'] != null ? DateTime.tryParse(map['eveningRevealedAt'] as String) : null, ); String toJson() => json.encode(toMap()); factory WordOfDayRecord.fromJson(String source) => WordOfDayRecord.fromMap(json.decode(source) as Map); }