import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:em2rp/models/vehicle_model.dart'; import 'package:em2rp/services/vehicle_service.dart'; import 'package:em2rp/utils/colors.dart'; class VehiclesManagement extends StatefulWidget { const VehiclesManagement({super.key}); @override State createState() => _VehiclesManagementState(); } class _VehiclesManagementState extends State { final _service = VehicleService(); bool _isLoading = false; static const _fuelTypes = ['Diesel', 'Essence', 'Electrique']; void _showVehicleDialog({VehicleModel? vehicle}) { final formKey = GlobalKey(); final nameCtrl = TextEditingController(text: vehicle?.name ?? ''); final consoCtrl = TextEditingController( text: vehicle?.consumptionPer100km.toString() ?? ''); final maintCtrl = TextEditingController( text: vehicle?.maintenanceCostPerKm.toString() ?? ''); String fuelType = vehicle?.fuelType ?? 'Diesel'; int tollCategory = vehicle?.tollCategoryId ?? 2; showDialog( context: context, builder: (ctx) => StatefulBuilder(builder: (ctx, setDlg) { return AlertDialog( title: Text(vehicle == null ? 'Ajouter un véhicule' : 'Modifier le véhicule'), content: SizedBox( width: 480, child: Form( key: formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ // Nom TextFormField( controller: nameCtrl, decoration: const InputDecoration( labelText: 'Nom du véhicule *', border: OutlineInputBorder(), prefixIcon: Icon(Icons.directions_car_outlined), hintText: 'ex: Renault Master', ), validator: (v) => v == null || v.trim().isEmpty ? 'Requis' : null, ), const SizedBox(height: 14), // Type de carburant DropdownButtonFormField( value: fuelType, decoration: const InputDecoration( labelText: 'Type de carburant *', border: OutlineInputBorder(), prefixIcon: Icon(Icons.local_gas_station_outlined), ), items: _fuelTypes .map((f) => DropdownMenuItem(value: f, child: Text(f))) .toList(), onChanged: (v) => setDlg(() => fuelType = v!), ), const SizedBox(height: 14), // Consommation TextFormField( controller: consoCtrl, decoration: InputDecoration( labelText: fuelType == 'Electrique' ? 'Consommation (kWh/100km) *' : 'Consommation (L/100km) *', border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.speed_outlined), ), keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'^\d+\.?\d{0,2}')) ], validator: (v) { if (v == null || v.isEmpty) return 'Requis'; if (double.tryParse(v) == null) return 'Nombre invalide'; return null; }, ), const SizedBox(height: 14), // Coût maintenance TextFormField( controller: maintCtrl, decoration: const InputDecoration( labelText: 'Coût maintenance (€/km) *', border: OutlineInputBorder(), prefixIcon: Icon(Icons.build_outlined), hintText: 'ex: 0.08', ), keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'^\d+\.?\d{0,3}')) ], validator: (v) { if (v == null || v.isEmpty) return 'Requis'; if (double.tryParse(v) == null) return 'Nombre invalide'; return null; }, ), const SizedBox(height: 14), // Catégorie péage Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Catégorie de péage : $tollCategory', style: const TextStyle(fontWeight: FontWeight.w500), ), const SizedBox(height: 4), Row( children: List.generate(5, (i) { final cat = i + 1; return Expanded( child: GestureDetector( onTap: () => setDlg(() => tollCategory = cat), child: Container( margin: const EdgeInsets.symmetric(horizontal: 3), padding: const EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration( color: tollCategory == cat ? AppColors.rouge : Colors.grey[200], borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( '$cat', style: TextStyle( color: tollCategory == cat ? Colors.white : Colors.black87, fontWeight: FontWeight.bold, ), ), ), ), ), ); }), ), const SizedBox(height: 4), Text( 'Classe 1 – Véhicules légers\n' 'Classe 2 – Véhicules intermédiaires\n' 'Classe 3 – Poids lourds, autocars et autres véhicules à 2 essieux\n' 'Classe 4 - Poids lourds et autres véhicules à 3 essieux et plus\n' 'Classe 5 – Motos, side-cars et trikes', style: TextStyle(fontSize: 11, color: Colors.grey[600]), ), ], ), ], ), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: const Text('Annuler'), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppColors.rouge, foregroundColor: Colors.white, ), onPressed: () async { if (!formKey.currentState!.validate()) return; Navigator.pop(ctx); setState(() => _isLoading = true); try { final v = VehicleModel( id: vehicle?.id ?? '', name: nameCtrl.text.trim(), fuelType: fuelType, consumptionPer100km: double.parse(consoCtrl.text.trim()), maintenanceCostPerKm: double.parse(maintCtrl.text.trim()), tollCategoryId: tollCategory, ); if (vehicle == null) { await _service.addVehicle(v); } else { await _service.updateVehicle(v); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Erreur: $e'), backgroundColor: Colors.red), ); } } finally { if (mounted) setState(() => _isLoading = false); } }, child: Text(vehicle == null ? 'Ajouter' : 'Enregistrer'), ), ], ); }), ); } Future _delete(VehicleModel v) async { final confirm = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Supprimer le véhicule'), content: Text('Supprimer "${v.name}" ?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('Annuler')), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white), onPressed: () => Navigator.pop(ctx, true), child: const Text('Supprimer'), ), ], ), ); if (confirm == true) { setState(() => _isLoading = true); try { await _service.deleteVehicle(v.id); } finally { if (mounted) setState(() => _isLoading = false); } } } Icon _fuelIcon(String fuelType) { switch (fuelType) { case 'Electrique': return const Icon(Icons.electric_bolt, color: Colors.amber); case 'Essence': return const Icon(Icons.local_gas_station, color: Colors.green); default: return const Icon(Icons.local_gas_station, color: Colors.orange); } } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.directions_car_outlined, color: AppColors.rouge, size: 28), const SizedBox(width: 12), Text( 'Véhicules', style: Theme.of(context) .textTheme .headlineSmall ?.copyWith(fontWeight: FontWeight.bold), ), const Spacer(), ElevatedButton.icon( icon: const Icon(Icons.add), label: const Text('Ajouter un véhicule'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.rouge, foregroundColor: Colors.white, ), onPressed: () => _showVehicleDialog(), ), ], ), const SizedBox(height: 8), Text( 'Paramétrez la flotte de véhicules pour le calcul automatique des frais de déplacement.', style: Theme.of(context) .textTheme .bodyMedium ?.copyWith(color: Colors.grey[600]), ), const SizedBox(height: 24), if (_isLoading) const LinearProgressIndicator(), Expanded( child: StreamBuilder>( stream: _service.watchVehicles(), builder: (context, snap) { if (snap.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } final vehicles = snap.data ?? []; if (vehicles.isEmpty) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.directions_car_outlined, size: 64, color: Colors.grey[300]), const SizedBox(height: 16), Text( 'Aucun véhicule', style: Theme.of(context) .textTheme .titleMedium ?.copyWith(color: Colors.grey[500]), ), const SizedBox(height: 8), const Text('Ajoutez des véhicules pour commencer.'), ], ), ); } return ListView.separated( itemCount: vehicles.length, separatorBuilder: (_, __) => const Divider(height: 1), itemBuilder: (ctx, i) { final v = vehicles[i]; return ListTile( leading: CircleAvatar( backgroundColor: Colors.grey[100], child: _fuelIcon(v.fuelType), ), title: Text(v.name, style: const TextStyle(fontWeight: FontWeight.w600)), subtitle: Text( '${v.consumptionPer100km} ${v.consumptionUnit} • Maint. ${v.maintenanceCostPerKm} €/km • Classe péage ${v.tollCategoryId}', ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Chip( label: Text(v.fuelType), backgroundColor: v.fuelType == 'Electrique' ? Colors.amber[50] : v.fuelType == 'Essence' ? Colors.green[50] : Colors.orange[50], side: BorderSide.none, ), IconButton( icon: const Icon(Icons.edit_outlined), tooltip: 'Modifier', onPressed: () => _showVehicleDialog(vehicle: v), ), IconButton( icon: const Icon(Icons.delete_outline, color: Colors.red), tooltip: 'Supprimer', onPressed: () => _delete(v), ), ], ), ); }, ); }, ), ), ], ), ); } }