import 'package:flutter/material.dart'; import '../../core/theme/app_colors.dart'; /// Model representing a Curriculum Subject (المادة الدراسية) class SubjectModel { final String id; final String title; final String englishTitle; final String iconCode; final Color primaryColor; final Color secondaryColor; final String gradeLevel; final String stream; final int totalUnits; final int totalLessons; final double masteryScore; // 0 - 100% final List units; final List textbooks; final List worksheets; final List exams; const SubjectModel({ required this.id, required this.title, required this.englishTitle, required this.iconCode, required this.primaryColor, required this.secondaryColor, this.gradeLevel = 'grade_10', this.stream = 'scientific', this.totalUnits = 0, this.totalLessons = 0, this.masteryScore = 0, this.units = const [], this.textbooks = const [], this.worksheets = const [], this.exams = const [], }); List get semester1Units => units.where((u) => u.semester == 'semester_1').toList(); List get semester2Units => units.where((u) => u.semester == 'semester_2').toList(); List unitsForSemester(String semesterKey) { final filtered = units.where((u) => u.semester == semesterKey).toList(); return filtered.isNotEmpty ? filtered : units; } factory SubjectModel.fromJson(String id, Map json) { var title = json['name']?.toString() ?? json['title']?.toString() ?? id; if (id == 'history_10' || title.contains('تاريخ الأردن')) { title = 'التاريخ (History 10)'; } final englishTitle = json['english_name']?.toString() ?? ''; // Parse units if available final List parsedUnits = []; if (json['semesters'] != null && json['semesters'] is Map) { final semesters = json['semesters'] as Map; semesters.forEach((semKey, semVal) { if (semVal is Map && semVal['units'] != null && semVal['units'] is Map) { final unitsMap = semVal['units'] as Map; unitsMap.forEach((uKey, uVal) { if (uVal is Map) { parsedUnits.add(CurriculumUnitModel.fromJson( uKey.toString(), Map.from(uVal), semester: semKey.toString(), )); } }); } }); } // Parse textbooks final List parsedTextbooks = []; final List parsedWorksheets = []; if (json['resources'] != null && json['resources'] is Map) { final res = json['resources'] as Map; if (res['textbooks'] != null && res['textbooks']['items'] is List) { for (var item in res['textbooks']['items']) { if (item is Map) { parsedTextbooks.add(ResourceItemModel.fromJson(Map.from(item))); } } } if (res['worksheets'] != null && res['worksheets']['items'] is List) { for (var item in res['worksheets']['items']) { if (item is Map) { parsedWorksheets.add(ResourceItemModel.fromJson(Map.from(item))); } } } } final styling = getSubjectStyling(id); return SubjectModel( id: id, title: title, englishTitle: englishTitle.isNotEmpty ? englishTitle : styling.englishTitle, iconCode: styling.iconCode, primaryColor: styling.primaryColor, secondaryColor: styling.secondaryColor, gradeLevel: json['grade_level']?.toString() ?? 'grade_10', stream: json['stream']?.toString() ?? 'scientific', totalUnits: parsedUnits.isNotEmpty ? parsedUnits.length : styling.defaultUnits, totalLessons: parsedUnits.fold(0, (sum, u) => sum + u.lessons.length), masteryScore: (json['mastery_score'] as num?)?.toDouble() ?? 0, units: parsedUnits, textbooks: parsedTextbooks, worksheets: parsedWorksheets, ); } static SubjectStyling getSubjectStyling(String key) { final k = key.toLowerCase(); if (k.contains('math') || k.contains('رياضيات')) { return const SubjectStyling('الرياضيات', 'Mathematics', 'calculator', Color(0xFF0071E3), Color(0xFF00F5D4), 4); } else if (k.contains('arabic') || k.contains('عربي') || k.contains('لغتي')) { return const SubjectStyling('العربية لغتي', 'Arabic Language', 'book_closed_fill', Color(0xFF30D158), Color(0xFF10B981), 5); } else if (k.contains('english') || k.contains('انجليز') || k.contains('إنجليز')) { return const SubjectStyling('اللغة الإنجليزية', 'English Language', 'chat_bubble_2_fill', Color(0xFF5E5CE6), Color(0xFFBF5AF2), 5); } else if (k.contains('islamic') || k.contains('إسلامي') || k.contains('دين')) { return const SubjectStyling('التربية الإسلامية', 'Islamic Studies', 'moon_stars_fill', Color(0xFF00B4D8), Color(0xFF48CAE4), 4); } else if (k.contains('physic') || k.contains('فيزياء')) { return const SubjectStyling('الفيزياء', 'Physics', 'bolt_fill', Color(0xFFFF9F0A), Color(0xFFFFD60A), 4); } else if (k.contains('chem') || k.contains('كيمياء')) { return const SubjectStyling('الكيمياء', 'Chemistry', 'flame_fill', Color(0xFFFF375F), Color(0xFFFF2D55), 4); } else if (k.contains('bio') || k.contains('أحياء') || k.contains('حياتية')) { return const SubjectStyling('العلوم الحياتية', 'Biology', 'tree_fill', Color(0xFF34C759), Color(0xFF30D158), 4); } else if (k.contains('earth') || k.contains('أرض') || k.contains('بيئة') || k.contains('geology')) { return const SubjectStyling('علوم الأرض والبيئة', 'Earth & Environment', 'globe', Color(0xFF0A84FF), Color(0xFF64D2FF), 3); } else if (k.contains('history') || k.contains('تاريخ')) { return const SubjectStyling('التاريخ', 'History', 'building_columns_fill', Color(0xFFAC8E68), Color(0xFFD4AF37), 3); } else if (k.contains('geo') || k.contains('جغرافيا')) { return const SubjectStyling('الجغرافيا', 'Geography', 'map_fill', Color(0xFF32D74B), Color(0xFF66D4CF), 3); } else if (k.contains('civic') || k.contains('وطنية') || k.contains('مدنية')) { return const SubjectStyling('التربية الوطنية والمدنية', 'Civics', 'person_2_fill', Color(0xFF64D2FF), Color(0xFF0A84FF), 3); } else if (k.contains('digital') || k.contains('حاسوب') || k.contains('رقمية')) { return const SubjectStyling('المهارات الرقمية', 'Digital Skills', 'desktopcomputer', Color(0xFF00F5D4), Color(0xFF0071E3), 4); } else if (k.contains('finance') || k.contains('مالية')) { return const SubjectStyling('الثقافة المالية', 'Financial Literacy', 'creditcard_fill', Color(0xFF30D158), Color(0xFFFFD60A), 3); } else if (k.contains('vocational') || k.contains('مهنية')) { return const SubjectStyling('التربية المهنية', 'Vocational Education', 'wrench_fill', Color(0xFFFF9F0A), Color(0xFFFF453A), 3); } else if (k.contains('art') || k.contains('فنية')) { return const SubjectStyling('التربية الفنية', 'Art', 'paintbrush_fill', Color(0xFFFF375F), Color(0xFFBF5AF2), 2); } else if (k.contains('sport') || k.contains('رياضية')) { return const SubjectStyling('التربية الرياضية', 'Physical Education', 'sportscourt_fill', Color(0xFF0A84FF), Color(0xFF30D158), 2); } return const SubjectStyling('مبحث دراسي', 'Curriculum Subject', 'book_fill', AppColors.appleBlue, AppColors.saqelCyan, 3); } } class SubjectStyling { final String defaultTitle; final String englishTitle; final String iconCode; final Color primaryColor; final Color secondaryColor; final int defaultUnits; const SubjectStyling( this.defaultTitle, this.englishTitle, this.iconCode, this.primaryColor, this.secondaryColor, this.defaultUnits, ); } /// Model representing a Curriculum Unit (الوحدة الدراسية) class CurriculumUnitModel { final String id; final String name; final String semester; final List lessons; const CurriculumUnitModel({ required this.id, required this.name, this.semester = 'semester_1', this.lessons = const [], }); factory CurriculumUnitModel.fromJson(String id, Map json, {String semester = 'semester_1'}) { final List parsedLessons = []; if (json['lessons'] != null && json['lessons'] is List) { for (var l in json['lessons']) { if (l is Map) { parsedLessons.add(CurriculumLessonItemModel.fromJson(Map.from(l))); } } } return CurriculumUnitModel( id: id, name: json['name']?.toString() ?? id, semester: semester, lessons: parsedLessons, ); } } /// Model representing a Lesson Item inside a Unit class CurriculumLessonItemModel { final String id; final String title; final List outcomes; final String? markdownFilePath; final String? curriculumLessonId; final int durationSeconds; final int checkpointsCount; final bool isCompleted; final bool hasVideo; const CurriculumLessonItemModel({ required this.id, required this.title, this.outcomes = const [], this.markdownFilePath, this.curriculumLessonId, this.durationSeconds = 0, this.checkpointsCount = 0, this.isCompleted = false, this.hasVideo = false, }); factory CurriculumLessonItemModel.fromJson(Map json) { final outcomesRaw = json['outcomes']; final List outs = []; if (outcomesRaw is List) { for (var o in outcomesRaw) { if (o != null) outs.add(o.toString()); } } final filePath = json['file']?.toString(); final jsonId = json['id']?.toString(); // Stable, deterministic lesson ID (vital for persistent per-lesson progress tracking) final stableId = (jsonId != null && jsonId.isNotEmpty) ? jsonId : (filePath != null && filePath.isNotEmpty ? filePath.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_') : 'lesson_${(json['title']?.toString() ?? 'default').hashCode.abs()}'); // Only the server may declare a published lesson playable. final bool hasVideoExplicit = json['has_video'] == true; return CurriculumLessonItemModel( id: stableId, title: json['title']?.toString() ?? 'درس بدون عنوان', outcomes: outs, markdownFilePath: filePath, curriculumLessonId: json['curriculum_lesson_id']?.toString(), durationSeconds: (json['duration_seconds'] as num?)?.toInt() ?? 0, checkpointsCount: (json['checkpoints_count'] as num?)?.toInt() ?? 0, isCompleted: (json['is_completed'] as bool?) ?? false, hasVideo: hasVideoExplicit, ); } } /// Model representing a Resource Item (PDF Textbook or Worksheet) class ResourceItemModel { final String title; final String assetId; final String assetType; final String mimeType; final String type; // textbook, worksheet, summary const ResourceItemModel({ required this.title, required this.assetId, required this.assetType, required this.mimeType, this.type = 'textbook', }); factory ResourceItemModel.fromJson(Map json) { return ResourceItemModel( title: json['title']?.toString() ?? 'ملف وزاري', assetId: json['asset_id']?.toString() ?? '', assetType: json['asset_type']?.toString() ?? 'other', mimeType: json['mime_type']?.toString() ?? '', type: json['type']?.toString() ?? 'textbook', ); } } /// Model representing an Exam / Question Bank item for the subject class SubjectExamModel { final String id; final String title; final int questionsCount; final int durationMinutes; final double targetScore; final String difficulty; // easy, medium, hard, ministerial const SubjectExamModel({ required this.id, required this.title, this.questionsCount = 20, this.durationMinutes = 40, this.targetScore = 100.0, this.difficulty = 'ministerial', }); }