import 'dart:convert'; import 'package:injectable/injectable.dart'; import 'package:mnemo_cards_backend/database/database.dart'; import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart'; import 'package:mnemo_cards_backend/tests/generators/models/creation_test_data.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:drift/drift.dart' as drift; import 'generators/pack_test_generator.dart'; @lazySingleton class TestManager { final AppDatabase _db; TestManager(this._db); Future _testStatisticsDto( String userId, String testId) async { final statistics = await _db.testDao.getTestStatistics(userId, testId); if (statistics == null) return null; // Convert TestStatistic to TestStatisticsDto // results is stored as Map with 'attempts' key final results = statistics.results ?? {}; final attempts = (results['attempts'] as List?) ?? []; // Get words from the last attempt, or empty list if no attempts final lastAttempt = attempts.isNotEmpty ? attempts.last as Map? : null; final wordsJson = (lastAttempt?['words'] as List?) ?? []; // Convert words JSON to WordStatisticsDto final words = wordsJson .map((w) => WordStatisticsDto.fromJson(w as Map)) .toList(); return TestStatisticsDto( testId: statistics.testId, words: AllWordsStatisticsDto(words: words), attempts: attempts.length, sessionToken: lastAttempt?['sessionToken'] as String?, ); } Future fetchTest(String id, UserModel user) async { final testId = id; final test = await _db.testDao.getTestById(testId); if (test == null) return null; final questions = await _db.testDao.getTestQuestions(testId); final statistics = await _testStatisticsDto(user.id!, testId); // Convert Test to TestDto final questionsList = questions.map((q) { // Parse question body based on type final body = json.decode(q.body) as Map; return AbstractTestQuestion.fromJson({ 'questionType': q.questionType, ...body, }); }).toList(); return TestDto( id: testId.toString(), name: test.name, color: test.color, cover: test.cover, version: test.version ?? '1.0', time: test.time, timeSubtitle: test.timeSubtitle, questions: questionsList, statistics: statistics, ); } Future> availableTests(UserModel userModel) async { final tests = await _db.testDao.getAllTests(); final testDtos = []; for (final test in tests) { final questions = await _db.testDao.getTestQuestions(test.id); final statistics = await _testStatisticsDto(userModel.id!, test.id); final questionsList = questions.map((q) { final body = json.decode(q.body) as Map; return AbstractTestQuestion.fromJson({ 'questionType': q.questionType, ...body, }); }).toList(); testDtos.add(TestDto( id: test.id.toString(), name: test.name, color: test.color, cover: test.cover, version: test.version ?? '1.0', time: test.time, timeSubtitle: test.timeSubtitle, questions: questionsList, statistics: statistics, )); } return testDtos; } Future> fetchPackTests( UserModel user, CardPackModel model, ) async { final packId = model.id; if (packId == null) return []; final tests = await _db.testDao.getTestsByPackId(packId); final testDtos = []; for (final test in tests) { final questions = await _db.testDao.getTestQuestions(test.id); final statistics = await _testStatisticsDto(user.id!, test.id); final questionsList = questions.map((q) { final body = json.decode(q.body) as Map; return AbstractTestQuestion.fromJson({ 'questionType': q.questionType, ...body, }); }).toList(); testDtos.add(TestDto( id: test.id.toString(), name: test.name, color: test.color, cover: test.cover, version: test.version ?? '1.0', time: test.time, timeSubtitle: test.timeSubtitle, questions: questionsList, statistics: statistics, )); } return testDtos; } Future refreshCustomCreationTestsData() async { // Load custom creation test data from database // For now, keep it simple } Future updateGeneratedTests(CardPackModel model) async { final packId = model.id; if (packId == null) return; // Get pack data from database final pack = await _db.packDao.getPackById(packId); if (pack == null) return; // Get all cards for the pack final cards = await _db.packDao.getPackCards(packId); if (cards.isEmpty) return; // Create creation test data final testDataItems = cards.map((card) { return TestDataItem( id: card.id.toString(), original: card.original, translation: card.translation, image: card.image, audio: card.original, // Use original as audio ); }).toList(); final creationTestData = CreationTestData( items: testDataItems, title: pack.title, color: pack.color, packId: packId.toString(), ); // Generate test using PackTestGenerator final generator = PackTestGenerator(creationTestData); final testDto = await generator.generate( name: '${pack.title} Test', ratios: { TestQuestionType.simple: 0.7, TestQuestionType.input_buttons: 0.3, }, multiply: 1.0, ); // Save test to database await addTest(testDto); // Link test to pack await _db.testDao.linkTestToPack(testDto.id!, packId); } Future addTest(TestDto testDto) async { await _db.transaction(() async { // Create test final testCompanion = TestsCompanion.insert( name: testDto.name, color: drift.Value(testDto.color), cover: drift.Value(testDto.cover), version: drift.Value(testDto.version), time: drift.Value(testDto.time), timeSubtitle: drift.Value(testDto.timeSubtitle), ); final testId = await _db.testDao.createTest(testCompanion); // Create questions for (final question in testDto.questions) { final questionCompanion = TestQuestionsCompanion.insert( testId: testId, questionType: question.questionType.name, body: json.encode(question.toJson()), ); await _db.testDao.createTestQuestion(questionCompanion); } }); } }