import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../../data/models/directorate_models.dart'; import '../../services/directorate_api_service.dart'; class SchoolPrincipalScreen extends StatefulWidget { const SchoolPrincipalScreen({super.key}); @override State createState() => _SchoolPrincipalScreenState(); } class _SchoolPrincipalScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; bool _isLoading = true; Map? _dashboardData; // Recording State bool _isRecording = false; int _recordDurationSeconds = 0; Timer? _recordTimer; double _recordedSizeMb = 0.0; String _selectedTeacher = 'أحمد المجالي'; String _selectedSubject = 'الفيزياء'; final TextEditingController _lessonTitleController = TextEditingController(text: 'قوانين نيوتن في الحركة والمصاعد'); RecordedLessonResult? _lastResult; // Exam state bool _examPushedToLab = false; bool _isPanoramicActive = false; double _panoramicSizeMb = 16.5; // Enterprise Integrity, Parent Reports & Roster State bool _isRunningIntegrityAudit = false; Map? _integrityResult; bool _isDispatchingParentReports = false; bool _isImportingRoster = false; @override void initState() { super.initState(); _tabController = TabController(length: 3, vsync: this); _loadData(); } Future _loadData() async { setState(() => _isLoading = true); final data = await DirectorateApiService.fetchSchoolDashboard(); if (mounted) { setState(() { _dashboardData = data; _isLoading = false; }); } } void _startRecording() { setState(() { _isRecording = true; _recordDurationSeconds = 0; _recordedSizeMb = 0.0; _lastResult = null; }); _recordTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (!mounted) return; setState(() { _recordDurationSeconds++; // Calculate simulated file size at 720p ~ 1.1 Mbps (approx 0.14 MB per second) _recordedSizeMb = (_recordDurationSeconds * 0.14).clamp(0.0, 395.0); }); }); } Future _stopAndAuditRecording() async { _recordTimer?.cancel(); setState(() => _isRecording = false); // Show quick processing dialog showCupertinoDialog( context: context, barrierDismissible: false, builder: (ctx) => const Center( child: CupertinoActivityIndicator(radius: 20), ), ); final result = await DirectorateApiService.recordLesson( teacherName: _selectedTeacher, subject: _selectedSubject, lessonTitle: _lessonTitleController.text.trim(), fileSizeMb: _recordedSizeMb > 0 ? _recordedSizeMb : 340.0, durationMinutes: (_recordDurationSeconds / 60).ceil().clamp(15, 45), ); if (mounted) { Navigator.of(context).pop(); // dismiss loading setState(() { _lastResult = result; }); } } void _showDualFormsPreview() async { await DirectorateApiService.fetchDualForms(); if (!mounted) return; showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (ctx) => Directionality( textDirection: TextDirection.rtl, child: Container( height: MediaQuery.of(context).size.height * 0.8, decoration: const BoxDecoration( color: Color(0xFF0F172A), borderRadius: BorderRadius.vertical(top: Radius.circular(24)), border: Border(top: BorderSide(color: Color(0xFF8B5CF6), width: 2)), ), padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Center( child: Container( width: 40, height: 4, decoration: BoxDecoration( color: const Color(0xFF334155), borderRadius: BorderRadius.circular(2), ), ), ), const SizedBox(height: 14), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'معاينة النماذج الموحدة (نموذج أ ونموذج ب)', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w800, color: Colors.white, ), ), IconButton( icon: const Icon(CupertinoIcons.xmark, color: Colors.white70), onPressed: () => Navigator.of(context).pop(), ), ], ), const SizedBox(height: 10), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFF1E1B4B), borderRadius: BorderRadius.circular(10), border: Border.all(color: const Color(0xFF8B5CF6).withOpacity(0.3)), ), child: const Text( 'المخطط الهجين: 70% أسئلة موضوعية مبرمجة على محطات الحاسوب + 30% خطوات إنشائية ورقية مطبوعة مع باركود تسلسلي مشفر.', style: TextStyle(fontSize: 12, color: Color(0xFFC4B5FD), height: 1.4), ), ), const SizedBox(height: 14), Expanded( child: Row( children: [ // Form A Card Expanded( child: Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: const Color(0xFF161F30), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF10B981).withOpacity(0.5)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(CupertinoIcons.doc_checkmark_fill, color: Color(0xFF10B981), size: 16), SizedBox(width: 6), Text('النموذج (أ) — الفا', style: TextStyle(fontWeight: FontWeight.w800, color: Color(0xFF34D399), fontSize: 13)), ], ), const SizedBox(height: 8), const Text('الباركود التسلسلي:\nSAQEL-EXAM-A-ALPHA', style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8))), const Divider(color: Color(0xFF1E293B)), const Text('• 20 مسألة موضوعية (70 علامة)\n• مسألتان إنشائيتان (30 علامة)\n• باركود موجه لكاميرا المشرف', style: TextStyle(fontSize: 11.5, color: Colors.white70, height: 1.6)), ], ), ), ), const SizedBox(width: 10), // Form B Card Expanded( child: Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: const Color(0xFF161F30), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF38BDF8).withOpacity(0.5)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(CupertinoIcons.doc_plaintext, color: Color(0xFF38BDF8), size: 16), SizedBox(width: 6), Text('النموذج (ب) — بيتا', style: TextStyle(fontWeight: FontWeight.w800, color: Color(0xFF38BDF8), fontSize: 13)), ], ), const SizedBox(height: 8), const Text('الباركود التسلسلي:\nSAQEL-EXAM-B-BETA', style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8))), const Divider(color: Color(0xFF1E293B)), const Text('• خلط كامل لترتيب الأسئلة\n• تغيير معطيات الأرقام للمقاعد المتجاورة لمنع النقل', style: TextStyle(fontSize: 11.5, color: Colors.white70, height: 1.6)), ], ), ), ), ], ), ), const SizedBox(height: 14), ElevatedButton.icon( onPressed: () { Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('🖨️ تم إرسال 48 نسخة من النموذج أ وب ومسودات الباركود لطابعة المدرسة المركزية'), backgroundColor: Color(0xFF10B981), ), ); }, icon: const Icon(CupertinoIcons.printer_fill, size: 16), label: const Text('أمر طباعة النماذج والباركود الآن'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8B5CF6), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ), ], ), ), ), ); } void _runIntegrityAudit() async { setState(() => _isRunningIntegrityAudit = true); final res = await DirectorateApiService.evaluateExamSessionIntegrity(); if (mounted) { setState(() { _integrityResult = res; _isRunningIntegrityAudit = false; }); } } void _dispatchParentReports() async { setState(() => _isDispatchingParentReports = true); final res = await DirectorateApiService.dispatchParentReports(); if (mounted) { setState(() => _isDispatchingParentReports = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(res['message'] ?? 'تم إرسال التقارير لأولياء الأمور بنجاح'), backgroundColor: const Color(0xFF10B981), ), ); } } void _importSchoolRoster() async { setState(() => _isImportingRoster = true); final res = await DirectorateApiService.importSchoolRoster(); if (mounted) { setState(() => _isImportingRoster = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('تم استيراد وتشفير ${res['imported_count']} طالباً بنجاح عبر AES-256-GCM السيادي 🔒'), backgroundColor: const Color(0xFF0284C7), ), ); } } @override void dispose() { _tabController.dispose(); _recordTimer?.cancel(); _lessonTitleController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { if (_isLoading) { return const Scaffold( backgroundColor: Color(0xFF070B12), body: Center( child: CupertinoActivityIndicator(color: Color(0xFF8B5CF6), radius: 18), ), ); } final school = _dashboardData?['school'] ?? {}; final teachers = (_dashboardData?['teachers'] as List? ?? []) .map((t) => TeacherItem.fromJson(t)) .toList(); return Scaffold( backgroundColor: const Color(0xFF070B12), appBar: AppBar( backgroundColor: const Color(0xFF0E1626), elevation: 0, centerTitle: false, title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( school['name'] ?? 'إدارة المدرسة العسكرية', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w700, color: Colors.white, ), ), const SizedBox(height: 2), Row( children: [ const Icon(CupertinoIcons.location_solid, size: 12, color: Color(0xFF94A3B8)), const SizedBox(width: 4), Text( school['governorate'] ?? 'العاصمة - عمان', style: const TextStyle(fontSize: 12, color: Color(0xFF94A3B8)), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(4), ), child: const Text( 'الفئة (ج) كبرى · 980 طالباً', style: TextStyle(fontSize: 11, color: Color(0xFFA78BFA)), ), ) ], ) ], ), bottom: TabBar( controller: _tabController, indicatorColor: const Color(0xFF8B5CF6), indicatorWeight: 3, labelColor: Colors.white, unselectedLabelColor: const Color(0xFF64748B), labelStyle: const TextStyle(fontWeight: FontWeight.w700, fontSize: 13.5), tabs: const [ Tab( icon: Icon(CupertinoIcons.video_camera_solid, size: 18), text: 'تسجيل الحصص الصفية', ), Tab( icon: Icon(CupertinoIcons.person_2_fill, size: 18), text: 'المعلمون والدورية', ), Tab( icon: Icon(CupertinoIcons.doc_text_fill, size: 18), text: 'الامتحانات ومختبر الحاسوب', ), ], ), ), body: TabBarView( controller: _tabController, children: [ _buildLessonRecordingTab(teachers), _buildTeachersQuotaTab(teachers), _buildUnifiedExamsTab(), ], ), ); } // --------------------------------------------------------------------------- // TAB 1: Classroom Video Recording & Pedagogical Quality Audit // --------------------------------------------------------------------------- Widget _buildLessonRecordingTab(List teachers) { return SingleChildScrollView( padding: const EdgeInsets.all(18), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Quota Banner Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( gradient: LinearGradient( colors: [const Color(0xFF1E1B4B), const Color(0xFF0F172A)], begin: Alignment.topRight, end: Alignment.bottomLeft, ), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF4338CA).withOpacity(0.5)), ), child: Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFF4F46E5).withOpacity(0.2), shape: BoxShape.circle, ), child: const Icon(CupertinoIcons.calendar_badge_plus, color: Color(0xFFA5B4FC), size: 24), ), const SizedBox(width: 14), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'دورية التدقيق الميداني المعتمدة', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white), ), SizedBox(height: 2), Text( 'حصة مرئية واحدة لكل معلم كل أسبوعين (الحد الأقصى للحجم: 400 ميجابايت بدقة 720p)', style: TextStyle(fontSize: 12, color: Color(0xFFCBD5E1)), ), ], ), ), ], ), ), const SizedBox(height: 18), // Camera Viewport Simulation Card Container( height: 240, decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(16), border: Border.all( color: _isRecording ? const Color(0xFFEF4444) : const Color(0xFF1E293B), width: _isRecording ? 2 : 1, ), boxShadow: _isRecording ? [ BoxShadow( color: const Color(0xFFEF4444).withOpacity(0.2), blurRadius: 20, spreadRadius: 2, ) ] : [], ), child: Stack( children: [ // Mock Classroom Background Grid Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( CupertinoIcons.videocam_fill, size: 54, color: _isRecording ? const Color(0xFFEF4444) : const Color(0xFF475569), ), const SizedBox(height: 10), Text( _isRecording ? 'جاري تصوير وقائع الحصة الصفية داخل الغرفة...' : 'كاميرا المشرف جاهزة للتسجيل الصفي', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: _isRecording ? Colors.white : const Color(0xFF94A3B8), ), ), const SizedBox(height: 4), Text( 'ترميز ذكي 720p · محدد تلقائياً لسقف 400 ميجابايت', style: TextStyle( fontSize: 12, color: const Color(0xFF64748B)), ), ], ), ), // Top Status Bar in Camera Positioned( top: 12, left: 12, right: 12, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (_isRecording) Row( children: [ Container( width: 10, height: 10, decoration: const BoxDecoration( color: Color(0xFFEF4444), shape: BoxShape.circle, ), ), const SizedBox(width: 6), const Text( 'تسجيل نشط (REC)', style: TextStyle( color: Color(0xFFEF4444), fontWeight: FontWeight.w800, fontSize: 12), ), ], ) else const Text( 'جاهز', style: TextStyle(color: Color(0xFF10B981), fontSize: 12), ), // Metrics Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.black.withOpacity(0.6), borderRadius: BorderRadius.circular(20), ), child: Text( _isRecording ? '${_formatDuration(_recordDurationSeconds)} | ${_recordedSizeMb.toStringAsFixed(1)} MB / 400 MB' : '00:00 | 0.0 MB', style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w700), ), ) ], ), ), // Bottom Action inside Camera Positioned( bottom: 14, left: 14, right: 14, child: ElevatedButton( onPressed: _isRecording ? _stopAndAuditRecording : _startRecording, style: ElevatedButton.styleFrom( backgroundColor: _isRecording ? const Color(0xFFDC2626) : const Color(0xFF8B5CF6), padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( _isRecording ? CupertinoIcons.stop_fill : CupertinoIcons.circle_fill, size: 18), const SizedBox(width: 8), Text( _isRecording ? 'إنهاء الحصة وإرسالها للتدقيق بالذكاء الاصطناعي 🚀' : 'بدء تصوير الحصة الصفية 🎥', style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w700), ), ], ), ), ), ], ), ), const SizedBox(height: 18), // Lesson Details Form Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF1E293B)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'بيانات الحصة والمعلم المستهدف:', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white), ), const SizedBox(height: 12), Row( children: [ Expanded( child: DropdownButtonFormField( value: _selectedTeacher, dropdownColor: const Color(0xFF1E293B), style: const TextStyle(color: Colors.white, fontSize: 13), decoration: InputDecoration( labelText: 'المعلم', labelStyle: const TextStyle(color: Color(0xFF94A3B8)), filled: true, fillColor: const Color(0xFF161F30), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), ), items: teachers .map((t) => DropdownMenuItem( value: t.name, child: Text(t.name))) .toList(), onChanged: (val) { if (val != null) setState(() => _selectedTeacher = val); }, ), ), const SizedBox(width: 12), Expanded( child: DropdownButtonFormField( value: _selectedSubject, dropdownColor: const Color(0xFF1E293B), style: const TextStyle(color: Colors.white, fontSize: 13), decoration: InputDecoration( labelText: 'المادة', labelStyle: const TextStyle(color: Color(0xFF94A3B8)), filled: true, fillColor: const Color(0xFF161F30), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), ), items: const [ DropdownMenuItem(value: 'الفيزياء', child: Text('الفيزياء')), DropdownMenuItem(value: 'الرياضيات', child: Text('الرياضيات')), DropdownMenuItem(value: 'الكيمياء', child: Text('الكيمياء')), DropdownMenuItem( value: 'اللغة الإنجليزية', child: Text('اللغة الإنجليزية')), ], onChanged: (val) { if (val != null) setState(() => _selectedSubject = val); }, ), ), ], ), const SizedBox(height: 12), TextField( controller: _lessonTitleController, style: const TextStyle(color: Colors.white, fontSize: 13.5), decoration: InputDecoration( labelText: 'عنوان الدرس وفق المنهاج الوزاري', labelStyle: const TextStyle(color: Color(0xFF94A3B8)), filled: true, fillColor: const Color(0xFF161F30), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), ), ), ], ), ), const SizedBox(height: 18), // AI Evaluation Card (if available) if (_lastResult != null) _buildAiResultCard(_lastResult!), ], ), ); } Widget _buildAiResultCard(RecordedLessonResult res) { return Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( color: const Color(0xFF111827), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF10B981).withOpacity(0.6)), boxShadow: [ BoxShadow( color: const Color(0xFF10B981).withOpacity(0.1), blurRadius: 20, ) ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Row( children: [ Icon(CupertinoIcons.checkmark_seal_fill, color: Color(0xFF10B981), size: 22), SizedBox(width: 8), Text( 'بطاقة التدقيق التربوي المعتمدة بالذكاء الاصطناعي', style: TextStyle( fontSize: 14.5, fontWeight: FontWeight.w700, color: Colors.white), ), ], ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: const Color(0xFF10B981).withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: Text( '${res.aiAlignmentScore}% مطابقة', style: const TextStyle( color: Color(0xFF10B981), fontWeight: FontWeight.w800, fontSize: 13), ), ), ], ), const SizedBox(height: 12), Text( res.reportSummary, style: const TextStyle( fontSize: 13, color: Color(0xFFCBD5E1), height: 1.5), ), const SizedBox(height: 14), Row( children: [ _metricChip('نسبة كلام المعلم', res.teacherTalkRatio), const SizedBox(width: 8), _metricChip('مدة الحصة', '${res.durationMinutes} دقيقة'), const SizedBox(width: 8), _metricChip('حجم الفيديو', '${res.fileSizeMb.toStringAsFixed(1)} MB'), ], ), const Divider(color: Color(0xFF1F2937), height: 24), const Text( 'الوقفات السقراطية المقترحة أثناء الحصة:', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w700, color: Color(0xFFA78BFA)), ), const SizedBox(height: 8), ...res.socraticCheckpoints.map((cp) => Container( margin: const EdgeInsets.only(bottom: 6), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Text( cp['timestamp'] ?? '', style: const TextStyle( color: Color(0xFFF59E0B), fontWeight: FontWeight.w700, fontSize: 12), ), const SizedBox(width: 10), Expanded( child: Text( cp['question'] ?? '', style: const TextStyle(color: Colors.white, fontSize: 12.5), ), ), ], ), )), ], ), ); } // --------------------------------------------------------------------------- // TAB 2: Teachers & Bi-Weekly Quota Tracking // --------------------------------------------------------------------------- Widget _buildTeachersQuotaTab(List teachers) { return ListView.builder( padding: const EdgeInsets.all(16), itemCount: teachers.length, itemBuilder: (ctx, idx) { final t = teachers[idx]; return Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF1E293B)), ), child: Row( children: [ CircleAvatar( radius: 22, backgroundColor: t.isCompleted ? const Color(0xFF10B981).withOpacity(0.2) : const Color(0xFFF59E0B).withOpacity(0.2), child: Text( t.name.split(' ').first, style: TextStyle( fontSize: 13, fontWeight: FontWeight.w700, color: t.isCompleted ? const Color(0xFF10B981) : const Color(0xFFF59E0B), ), ), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( t.name, style: const TextStyle( fontSize: 14.5, fontWeight: FontWeight.w700, color: Colors.white), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 1), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(4), ), child: Text( t.subject, style: const TextStyle( fontSize: 11, color: Color(0xFF94A3B8)), ), ), ], ), const SizedBox(height: 4), Text( 'آخر حصة: ${t.lastLesson}', style: const TextStyle(fontSize: 12, color: Color(0xFF64748B)), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: t.isCompleted ? const Color(0xFF065F46) : const Color(0xFF78350F), borderRadius: BorderRadius.circular(6), ), child: Text( t.isCompleted ? 'مكتمل الدورية' : 'متبقي هذا الأسبوع', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w700, color: t.isCompleted ? const Color(0xFF34D399) : const Color(0xFFFBBF24), ), ), ), const SizedBox(height: 4), Text( 'التقييم: ${t.aiScore}%', style: const TextStyle( fontSize: 11.5, color: Color(0xFFA78BFA), fontWeight: FontWeight.w600), ), ], ), ], ), ); }, ); } // --------------------------------------------------------------------------- // TAB 3: Unified Exams, Lab Dispatch & Smart Panoramic Surveillance // --------------------------------------------------------------------------- Widget _buildUnifiedExamsTab() { return SingleChildScrollView( padding: const EdgeInsets.all(18), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Active Exam Card Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( gradient: LinearGradient( colors: [const Color(0xFF1E293B), const Color(0xFF0F172A)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF8B5CF6).withOpacity(0.5)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Row( children: [ Icon(CupertinoIcons.doc_checkmark_fill, color: Color(0xFFA78BFA), size: 20), SizedBox(width: 8), Text( 'امتحان وزاري موحد من مديرية الثقافة العسكرية', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white), ), ], ), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFF8B5CF6).withOpacity(0.2), borderRadius: BorderRadius.circular(6), ), child: const Text( 'موعد موحد: 09:00 ص', style: TextStyle( fontSize: 11.5, color: Color(0xFFA78BFA), fontWeight: FontWeight.w700), ), ), ], ), const SizedBox(height: 12), const Text( 'الرياضيات العلمي - محاكاة امتحان التوجيهي الوزاري 2008', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: Colors.white), ), const SizedBox(height: 6), const Text( 'المدة: 60 دقيقة · جدول المواصفات الوزاري المعتمد · نموذجان (أ و ب)', style: TextStyle(fontSize: 12.5, color: Color(0xFF94A3B8)), ), const SizedBox(height: 16), // Lab Push & Print Buttons Row( children: [ Expanded( child: ElevatedButton.icon( onPressed: () async { final ok = await DirectorateApiService.pushExamToLab( 'EX-MC-2026-01'); if (ok && mounted) { setState(() => _examPushedToLab = true); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( '✅ تم بث الامتحان لمحطات مختبر الحاسوب وتفعيل البيئة المقفلة (Kiosk Mode)'), backgroundColor: Color(0xFF10B981), ), ); } }, icon: Icon( _examPushedToLab ? CupertinoIcons.checkmark_alt_circle_fill : CupertinoIcons.desktopcomputer, size: 16), label: Text( _examPushedToLab ? 'تم البث لمختبر الحاسوب' : 'إرسال لمختبر الحاسوب (32 جهازاً)', style: const TextStyle( fontSize: 12.5, fontWeight: FontWeight.w700), ), style: ElevatedButton.styleFrom( backgroundColor: _examPushedToLab ? const Color(0xFF059669) : const Color(0xFF4F46E5), padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), ), ), const SizedBox(width: 8), ElevatedButton.icon( onPressed: _showDualFormsPreview, icon: const Icon(CupertinoIcons.doc_on_doc_fill, size: 16), label: const Text('معاينة وطباعة النماذج (أ وب)', style: TextStyle(fontSize: 12.5)), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8B5CF6), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( vertical: 12, horizontal: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), ), ], ), ], ), ), const SizedBox(height: 18), // Smart Panoramic Surveillance Viewport Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(16), border: Border.all( color: _isPanoramicActive ? const Color(0xFFEF4444) : const Color(0xFF1E293B), width: _isPanoramicActive ? 2 : 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( width: 10, height: 10, decoration: BoxDecoration( color: _isPanoramicActive ? const Color(0xFFEF4444) : const Color(0xFF64748B), shape: BoxShape.circle, ), ), const SizedBox(width: 8), const Text( 'الرقابة البانورامية بتقنية التقطيع الزمني الذكي', style: TextStyle( fontSize: 13.5, fontWeight: FontWeight.w700, color: Colors.white), ), ], ), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(6), ), child: Text( 'الحجم: ${_panoramicSizeMb.toStringAsFixed(1)} MB فقط', style: const TextStyle( fontSize: 11.5, color: Color(0xFF38BDF8), fontWeight: FontWeight.w700), ), ), ], ), const SizedBox(height: 10), const Text( 'المبدأ: تظهر الكاميرا نشطة طوال الامتحان لفرض الردع النفسي، لكن التطبيق يقتطع ثانيتين فقط كل دقيقة لينتج مقطعاً مجمعاً مدته دقيقتان فقط بحجم 16.5 ميجابايت.', style: TextStyle( fontSize: 12, color: Color(0xFF94A3B8), height: 1.5), ), const SizedBox(height: 14), // Toggle Panoramic Button ElevatedButton.icon( onPressed: () { setState(() => _isPanoramicActive = !_isPanoramicActive); if (_isPanoramicActive) { DirectorateApiService.uploadPanoramicSample( fileSizeMb: _panoramicSizeMb, durationSeconds: 120, ); } }, icon: Icon( _isPanoramicActive ? CupertinoIcons.eye_slash_fill : CupertinoIcons.eye_fill, size: 16), label: Text( _isPanoramicActive ? 'إيقاف نمط الرقابة البانورامية' : 'تفعيل نمط الرقابة البانورامية في القاعة 👁️', style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w700), ), style: ElevatedButton.styleFrom( backgroundColor: _isPanoramicActive ? const Color(0xFFB91C1C) : const Color(0xFF0284C7), padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), ), ], ), ), const SizedBox(height: 18), // Anomaly Indicator Summary & Statistical Detection Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1E293B)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'مؤشرات الذكاء الإحصائي لكشف الشذوذ والتواطؤ:', style: TextStyle( fontSize: 13.5, fontWeight: FontWeight.w700, color: Colors.white), ), ElevatedButton.icon( onPressed: _isRunningIntegrityAudit ? null : _runIntegrityAudit, icon: _isRunningIntegrityAudit ? const SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(CupertinoIcons.waveform_path_ecg, size: 15), label: Text( _isRunningIntegrityAudit ? 'جاري الفحص...' : 'فحص النزاهة اللحظي ⚡', style: const TextStyle(fontSize: 11.5, fontWeight: FontWeight.w800), ), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF0284C7), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ), ], ), const SizedBox(height: 12), _buildAnomalyTile( title: 'مؤشر السرعة المستحيلة (أقل من 15 ثانية لمسألة تفاضل معقدة)', status: _integrityResult != null ? 'تم رصد حالة مشبوهة ⚠️' : 'سليم', isGood: _integrityResult == null, ), _buildAnomalyTile( title: 'مؤشر تكتل الأخطاء المتطابقة (خيارات خاطئة نادرة بين مقاعد متجاورة)', status: _integrityResult != null ? 'تطابق في مقعد 05 و 06 ⚠️' : 'سليم', isGood: _integrityResult == null, ), _buildAnomalyTile( title: 'مؤشر القفزة التاريخية المفاجئة (ارتفاع 45% دفعة واحدة)', status: _integrityResult != null ? 'حالة واحدة تتطلب مطابقة الخطوات الورقية ⚠️' : 'سليم', isGood: _integrityResult == null, ), // Live Anomalies Feed if (_integrityResult != null && (_integrityResult!['anomalies'] as List? ?? []).isNotEmpty) ...[ const Divider(color: Color(0xFF1E293B), height: 20), const Text('🚨 تنبيهات الشذوذ المكتشفة ومقترحات المشرف:', style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.w800, color: Color(0xFFEF4444))), const SizedBox(height: 8), ...((_integrityResult!['anomalies'] as List).take(2).map((anom) => Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFF7F1D1D).withOpacity(0.25), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFFEF4444).withOpacity(0.4)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('${anom['title']} · ${anom['student_name']} (${anom['seat_number']})', style: const TextStyle(fontSize: 11.5, fontWeight: FontWeight.w800, color: Color(0xFFFCA5A5))), const SizedBox(height: 4), Text(anom['details'] ?? '', style: const TextStyle(fontSize: 11, color: Colors.white70)), const SizedBox(height: 4), Text('الإجراء: ${anom['recommended_action']}', style: const TextStyle(fontSize: 10.5, color: Color(0xFFFBBF24), fontWeight: FontWeight.w700)), ], ), ))), ], ], ), ), const SizedBox(height: 18), // Monthly Parent Reports Dispatch Card (Nabeh WhatsApp Gateway) Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF064E3B), Color(0xFF0F172A)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF10B981).withOpacity(0.4)), ), child: Row( children: [ Container( width: 44, height: 44, decoration: BoxDecoration( color: const Color(0xFF10B981).withOpacity(0.2), shape: BoxShape.circle, ), child: const Icon(CupertinoIcons.chat_bubble_2_fill, color: Color(0xFF34D399), size: 22), ), const SizedBox(width: 14), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'بث تقارير أولياء الأمور عبر الواتساب (بوابة نبيه) 📲', style: TextStyle(fontSize: 13.5, fontWeight: FontWeight.w800, color: Colors.white), ), SizedBox(height: 3), Text( 'إرسال ومضة رقمية شهرية لـ 450 ولي أمر تتضمن الحضور ودفتر الأخطاء ودرجات الامتحان الموحد.', style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8), height: 1.3), ), ], ), ), const SizedBox(width: 8), ElevatedButton( onPressed: _isDispatchingParentReports ? null : _dispatchParentReports, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF10B981), foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: _isDispatchingParentReports ? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.black)) : const Text('بث الدفعة الآن', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w800)), ), ], ), ), const SizedBox(height: 14), // Encrypted School Roster Import Card (AES-256-GCM) Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0F172A), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1E293B)), ), child: Row( children: [ Container( width: 44, height: 44, decoration: BoxDecoration( color: const Color(0xFF38BDF8).withOpacity(0.2), shape: BoxShape.circle, ), child: const Icon(CupertinoIcons.lock_shield_fill, color: Color(0xFF38BDF8), size: 22), ), const SizedBox(width: 14), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'استيراد كشف المدرسة وتشفير الأرقام الوطنية 🔒', style: TextStyle(fontSize: 13.5, fontWeight: FontWeight.w800, color: Colors.white), ), SizedBox(height: 3), Text( 'تشفير فوري سيادي بـ AES-256-GCM مع التحقق من الـ 10 خانات الرقمية ومؤشر HMAC الأعمى.', style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8), height: 1.3), ), ], ), ), const SizedBox(width: 8), ElevatedButton( onPressed: _isImportingRoster ? null : _importSchoolRoster, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF0284C7), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: _isImportingRoster ? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Text('استيراد الكشف', style: TextStyle(fontSize: 12, fontWeight: FontWeight.w800)), ), ], ), ), ], ), ); } Widget _buildAnomalyTile( {required String title, required String status, required bool isGood}) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( children: [ Icon( isGood ? CupertinoIcons.check_mark_circled_solid : CupertinoIcons.exclamationmark_triangle_fill, color: isGood ? const Color(0xFF10B981) : const Color(0xFFEF4444), size: 16, ), const SizedBox(width: 8), Expanded( child: Text(title, style: const TextStyle(fontSize: 12.5, color: Colors.white)), ), Text( status, style: TextStyle( fontSize: 11.5, fontWeight: FontWeight.w600, color: isGood ? const Color(0xFF34D399) : const Color(0xFFF87171), ), ), ], ), ); } Widget _metricChip(String label, String value) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(6), ), child: Row( children: [ Text('$label: ', style: const TextStyle(fontSize: 11, color: Color(0xFF94A3B8))), Text(value, style: const TextStyle( fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white)), ], ), ); } String _formatDuration(int seconds) { final m = seconds ~/ 60; final s = seconds % 60; return '${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}'; } }