import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:words999/models/syncretic_session_model.dart'; import 'package:words999/models/word_of_day_model.dart'; import 'package:words999/services/word_of_the_day_service.dart'; import 'package:words999/services/words_repository.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUpAll(() async { SharedPreferences.setMockInitialValues({}); await WordsRepository().init(remoteDailyShuffle: false); await WordOfTheDayService().init(); }); group('WordOfTheDayService & Model Tests', () { test('Date key format and parse consistency', () { final date = DateTime(2026, 9, 28); final key = WordOfTheDayService.formatDateKey(date); expect(key, '2026-09-28'); final parsed = WordOfTheDayService.parseDateKey(key); expect(parsed.year, 2026); expect(parsed.month, 9); expect(parsed.day, 28); }); test('Deterministic daily word hash is consistent for identical dates', () { final date1 = DateTime(2026, 9, 28); final date2 = DateTime(2026, 9, 28, 23, 59, 59); final idx1 = WordOfTheDayService.calculateWordIndexForDate(date1, 1000); final idx2 = WordOfTheDayService.calculateWordIndexForDate(date2, 1000); expect(idx1, equals(idx2)); final word1 = WordOfTheDayService().getWordForDate(date1); final word2 = WordOfTheDayService().getWordForDate(date2); expect(word1.id, equals(word2.id)); expect(word1.word, equals(word2.word)); }); test('Adjacent dates yield distinct words across calendar', () { final day1 = DateTime(2026, 9, 27); final day2 = DateTime(2026, 9, 28); final day3 = DateTime(2026, 9, 29); final idx1 = WordOfTheDayService.calculateWordIndexForDate(day1, 1000); final idx2 = WordOfTheDayService.calculateWordIndexForDate(day2, 1000); final idx3 = WordOfTheDayService.calculateWordIndexForDate(day3, 1000); expect(idx1, isNot(equals(idx2))); expect(idx2, isNot(equals(idx3))); }); test('Triptych mode provides 3 distinct words for Morning, Day, and Evening', () { final date = DateTime(2026, 9, 28); final triptych = WordOfTheDayService().getTriptychWordsForDate(date); expect(triptych.morning.id, isNot(equals(triptych.day.id))); expect(triptych.day.id, isNot(equals(triptych.evening.id))); expect(triptych.morning.id, isNot(equals(triptych.evening.id))); }); test('WordOfDayRecord JSON serialization and copyWith with Triptych', () { const rec = WordOfDayRecord( dateKey: '2026-09-28', wordId: 42, isRevealed: true, isStepCompleted: false, diaryNote: 'Удивительная синхрония в разговоре', isTriptychMode: true, morningWordId: 10, dayWordId: 20, eveningWordId: 30, isMorningRevealed: true, isDayRevealed: true, isEveningRevealed: false, isDayStepCompleted: true, ); final jsonStr = rec.toJson(); final decoded = WordOfDayRecord.fromJson(jsonStr); expect(decoded.dateKey, '2026-09-28'); expect(decoded.wordId, 42); expect(decoded.isTriptychMode, isTrue); expect(decoded.morningWordId, 10); expect(decoded.dayWordId, 20); expect(decoded.eveningWordId, 30); expect(decoded.isMorningRevealed, isTrue); expect(decoded.isDayRevealed, isTrue); expect(decoded.isEveningRevealed, isFalse); expect(decoded.isDayStepCompleted, isTrue); expect(decoded.isAnyRevealed, isTrue); expect(decoded.areAllTriptychRevealed, isFalse); final allRevealed = decoded.copyWith(isEveningRevealed: true); expect(allRevealed.areAllTriptychRevealed, isTrue); }); test('Reveal specific triptych phases and persist', () async { final service = WordOfTheDayService(); final testDate = DateTime(2026, 11, 20); await service.setRecordTriptychMode(testDate, true); var rec = service.getRecord(testDate); expect(rec.isTriptychMode, isTrue); expect(rec.isMorningRevealed, isFalse); await service.revealWord(testDate, phase: 'morning'); rec = service.getRecord(testDate); expect(rec.isMorningRevealed, isTrue); expect(rec.isDayRevealed, isFalse); await service.revealWord(testDate, phase: 'day'); rec = service.getRecord(testDate); expect(rec.isDayRevealed, isTrue); expect(rec.isEveningRevealed, isFalse); await service.revealWord(testDate, phase: 'evening'); rec = service.getRecord(testDate); expect(rec.isEveningRevealed, isTrue); expect(rec.areAllTriptychRevealed, isTrue); await service.toggleStepCompleted(testDate, true, isDayStep: true); rec = service.getRecord(testDate); expect(rec.isDayStepCompleted, isTrue); }); test('SyncreticSession can incorporate Triptych reading', () async { final triptych = WordOfTheDayService().getTriptychWordsForDate(DateTime(2026, 9, 28)); final reading = SyncreticReading( id: 'trip_test_1', systemId: 'word_of_day', systemName: 'Триптих Дня', systemIcon: '⏳', timestamp: DateTime.now(), layoutTitle: 'Триптих Суток', items: [ ReadingSignItem( title: 'Утро: ${triptych.morning.word}', linkedWord: triptych.morning, ), ReadingSignItem( title: 'День: ${triptych.day.word}', linkedWord: triptych.day, ), ReadingSignItem( title: 'Вечер: ${triptych.evening.word}', linkedWord: triptych.evening, ), ], ); final repo = WordsRepository(); await repo.addReadingToSyncreticSession(reading); final current = repo.currentSyncreticSession; expect(current.readings.any((r) => r.id == 'trip_test_1'), isTrue); expect(current.readings.firstWhere((r) => r.id == 'trip_test_1').items.length, 3); }); }); }