import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import '../../core/constants/app_constants.dart'; import '../../core/theme/app_theme.dart'; import '../../data/models/weapon.dart'; import '../../data/repositories/session_repository.dart'; import 'session_provider.dart'; import '../capture/capture_screen.dart'; import '../garage/weapon_list_screen.dart'; class SessionSetupScreen extends StatefulWidget { const SessionSetupScreen({super.key}); @override State createState() => _SessionSetupScreenState(); } class _SessionSetupScreenState extends State { final _formKey = GlobalKey(); int _shotsPerTarget = 5; int _distance = 25; List _availableWeapons = []; Weapon? _selectedWeapon; bool _isLoadingWeapons = true; DateTime _selectedDate = DateTime.now(); static const List _presetDistances = [10, 15, 25, 50, 100, 200]; static const List _presetShots = [3, 5, 10, 15, 20, 30]; @override void initState() { super.initState(); _loadWeapons(); } Future _loadWeapons() async { setState(() => _isLoadingWeapons = true); final repository = context.read(); final weapons = await repository.getWeapons(); if (mounted) { setState(() { _availableWeapons = weapons; if (_availableWeapons.isNotEmpty && _selectedWeapon == null) { _selectedWeapon = _availableWeapons.first; _updateSettingsForWeapon(_selectedWeapon!); } _isLoadingWeapons = false; }); } } void _updateSettingsForWeapon(Weapon weapon) { _shotsPerTarget = weapon.magazineCapacity > 0 ? weapon.magazineCapacity : 5; _distance = (weapon.type == WeaponType.handgun) ? 25 : 50; } Future _pickDate() async { final DateTime? picked = await showDatePicker( context: context, initialDate: _selectedDate, firstDate: DateTime(2020), lastDate: DateTime(2100), locale: const Locale('fr', 'FR'), ); if (picked != null && picked != _selectedDate) { setState(() { final now = DateTime.now(); _selectedDate = DateTime( picked.year, picked.month, picked.day, now.hour, now.minute, ); }); } } void _startSession() { if (_formKey.currentState!.validate() && _selectedWeapon != null) { final repository = context.read(); final sessionProvider = context.read(); final sessionId = repository.generateId(); sessionProvider.startSession( _selectedWeapon!.displayName, _shotsPerTarget, sessionId, weaponId: _selectedWeapon!.id, distance: _distance, date: _selectedDate, ); Navigator.pushReplacement( context, MaterialPageRoute(builder: (_) => const CaptureScreen()), ); } } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; final formattedDate = DateFormat('dd MMMM yyyy • HH:mm', 'fr_FR').format(_selectedDate); return Scaffold( appBar: AppBar( title: const Text('Configuration de Session'), ), body: _isLoadingWeapons ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( padding: const EdgeInsets.all(AppConstants.defaultPadding), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (_availableWeapons.isEmpty) _buildEmptyArmoryState(isDark) else ...[ _buildWeaponAndDateSection(isDark, formattedDate), const SizedBox(height: 20), _buildDistanceSection(isDark), const SizedBox(height: 20), _buildShotsSection(isDark), const SizedBox(height: 32), _buildStartButton(), const SizedBox(height: 16), ], ], ), ), ), ); } Widget _buildEmptyArmoryState(bool isDark) { return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: isDark ? AppTheme.darkSurface : AppTheme.lightSurface, borderRadius: BorderRadius.circular(16), border: Border.all( color: AppTheme.errorColor.withValues(alpha: 0.5), ), ), child: Column( children: [ const Icon( Icons.warning_amber_rounded, color: AppTheme.errorColor, size: 52, ), const SizedBox(height: 12), Text( 'Armurerie vide', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), const SizedBox(height: 6), Text( 'Ajoutez au moins une arme dans votre armurerie pour débuter une séance.', textAlign: TextAlign.center, style: TextStyle( fontSize: 13, color: isDark ? AppTheme.darkTextSecondary : AppTheme.lightTextSecondary, ), ), const SizedBox(height: 20), ElevatedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (_) => const WeaponListScreen()), ).then((_) => _loadWeapons()); }, icon: const Icon(Icons.shield), label: const Text('Aller à l\'armurerie'), ), ], ), ); } Widget _buildWeaponAndDateSection(bool isDark, String formattedDate) { return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.tune, color: AppTheme.primaryColor, size: 20), const SizedBox(width: 8), Text( 'Arme & Date', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w700, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), ], ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: _selectedWeapon, decoration: const InputDecoration( labelText: 'Arme utilisée', prefixIcon: Icon(Icons.shield_outlined), ), items: _availableWeapons .map( (w) => DropdownMenuItem( value: w, child: Text('${w.displayName} (${w.caliber})'), ), ) .toList(), onChanged: (value) { if (value != null) { setState(() { _selectedWeapon = value; _updateSettingsForWeapon(value); }); } }, ), const SizedBox(height: 12), InkWell( onTap: _pickDate, borderRadius: BorderRadius.circular(12), child: IgnorePointer( child: TextFormField( decoration: const InputDecoration( labelText: 'Date de séance', prefixIcon: Icon(Icons.calendar_today_outlined), ), controller: TextEditingController(text: formattedDate), ), ), ), ], ), ), ); } Widget _buildDistanceSection(bool isDark) { return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ const Icon(Icons.straighten, color: AppTheme.secondaryColor, size: 20), const SizedBox(width: 8), Text( 'Distance de Tir', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w700, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), ], ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: AppTheme.secondaryColor.withValues(alpha: isDark ? 0.2 : 0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: AppTheme.secondaryColor.withValues(alpha: 0.4), ), ), child: Text( '${_distance}m', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: AppTheme.secondaryColor, ), ), ), ], ), const SizedBox(height: 12), Wrap( spacing: 8, runSpacing: 8, children: _presetDistances.map((d) { final isSelected = _distance == d; return ChoiceChip( label: Text('${d}m'), selected: isSelected, onSelected: (selected) { if (selected) setState(() => _distance = d); }, ); }).toList(), ), const SizedBox(height: 8), Slider( value: _distance.toDouble(), min: 5, max: 300, divisions: 59, activeColor: AppTheme.secondaryColor, onChanged: (val) { setState(() => _distance = val.round()); }, ), ], ), ), ); } Widget _buildShotsSection(bool isDark) { final primaryColor = Theme.of(context).colorScheme.primary; return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon(Icons.ads_click, color: primaryColor, size: 20), const SizedBox(width: 8), Text( 'Tirs par Cible', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w700, color: isDark ? AppTheme.darkTextPrimary : AppTheme.lightTextPrimary, ), ), ], ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: primaryColor.withValues(alpha: isDark ? 0.2 : 0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: primaryColor.withValues(alpha: 0.4), ), ), child: Text( '$_shotsPerTarget tirs', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: primaryColor, ), ), ), ], ), const SizedBox(height: 12), Wrap( spacing: 8, runSpacing: 8, children: _presetShots.map((s) { final isSelected = _shotsPerTarget == s; return ChoiceChip( label: Text('$s coups'), selected: isSelected, onSelected: (selected) { if (selected) setState(() => _shotsPerTarget = s); }, ); }).toList(), ), const SizedBox(height: 8), Slider( value: _shotsPerTarget.toDouble(), min: 1, max: 50, divisions: 49, activeColor: primaryColor, onChanged: (val) { setState(() => _shotsPerTarget = val.round()); }, ), ], ), ), ); } Widget _buildStartButton() { final primaryColor = Theme.of(context).colorScheme.primary; return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), gradient: LinearGradient( colors: [ primaryColor, HSLColor.fromColor(primaryColor).withLightness((HSLColor.fromColor(primaryColor).lightness + 0.15).clamp(0.0, 1.0)).toColor(), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: primaryColor.withValues(alpha: 0.35), blurRadius: 16, offset: const Offset(0, 4), ), ], ), child: ElevatedButton.icon( onPressed: (_availableWeapons.isEmpty || _selectedWeapon == null) ? null : _startSession, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, foregroundColor: Colors.white, shadowColor: Colors.transparent, padding: const EdgeInsets.symmetric(vertical: 18), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), ), icon: const Icon(Icons.play_arrow_rounded, size: 26), label: const Text( 'DÉMARRER LA SESSION', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, letterSpacing: 0.8, ), ), ), ); } }