import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:youmazgestion/Services/stock_managementDatabase.dart'; import '../Models/client.dart'; class ClientFormWidget extends StatefulWidget { final Function(Client) onClientSelected; final Client? initialClient; const ClientFormWidget({ Key? key, required this.onClientSelected, this.initialClient, }) : super(key: key); @override State createState() => _ClientFormWidgetState(); } class _ClientFormWidgetState extends State { final _formKey = GlobalKey(); final AppDatabase _database = AppDatabase.instance; // Contrôleurs de texte final TextEditingController _nomController = TextEditingController(); final TextEditingController _prenomController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _telephoneController = TextEditingController(); final TextEditingController _adresseController = TextEditingController(); // Variables d'état bool _isLoading = false; Client? _selectedClient; List _suggestions = []; bool _showSuggestions = false; String _searchQuery = ''; @override void initState() { super.initState(); if (widget.initialClient != null) { _fillClientData(widget.initialClient!); } // Écouter les changements dans les champs pour déclencher la recherche _emailController.addListener(_onEmailChanged); _telephoneController.addListener(_onPhoneChanged); _nomController.addListener(_onNameChanged); _prenomController.addListener(_onNameChanged); } @override void dispose() { _nomController.dispose(); _prenomController.dispose(); _emailController.dispose(); _telephoneController.dispose(); _adresseController.dispose(); super.dispose(); } void _fillClientData(Client client) { setState(() { _selectedClient = client; _nomController.text = client.nom; _prenomController.text = client.prenom; _emailController.text = client.email; _telephoneController.text = client.telephone; _adresseController.text = client.adresse ?? ''; }); } void _clearForm() { setState(() { _selectedClient = null; _nomController.clear(); _prenomController.clear(); _emailController.clear(); _telephoneController.clear(); _adresseController.clear(); _suggestions.clear(); _showSuggestions = false; }); } // Recherche par email void _onEmailChanged() async { final email = _emailController.text.trim(); if (email.length >= 3 && email.contains('@')) { _searchExistingClient(email: email); } } // Recherche par téléphone void _onPhoneChanged() async { final phone = _telephoneController.text.trim(); if (phone.length >= 4) { _searchExistingClient(telephone: phone); } } // Recherche par nom/prénom void _onNameChanged() async { final nom = _nomController.text.trim(); final prenom = _prenomController.text.trim(); if (nom.length >= 2 || prenom.length >= 2) { final query = '$nom $prenom'.trim(); if (query.length >= 2) { _getSuggestions(query); } } } // Rechercher un client existant Future _searchExistingClient({ String? email, String? telephone, String? nom, String? prenom, }) async { if (_selectedClient != null) return; // Éviter de chercher si un client est déjà sélectionné try { setState(() => _isLoading = true); final existingClient = await _database.findExistingClient( email: email, telephone: telephone, nom: nom, prenom: prenom, ); if (existingClient != null && mounted) { _showClientFoundDialog(existingClient); } } catch (e) { print('Erreur lors de la recherche: $e'); } finally { if (mounted) setState(() => _isLoading = false); } } // Obtenir les suggestions Future _getSuggestions(String query) async { if (query.length < 2) { setState(() { _suggestions.clear(); _showSuggestions = false; }); return; } try { final suggestions = await _database.suggestClients(query); if (mounted) { setState(() { _suggestions = suggestions; _showSuggestions = suggestions.isNotEmpty; _searchQuery = query; }); } } catch (e) { print('Erreur lors de la récupération des suggestions: $e'); } } // Afficher le dialogue de client trouvé void _showClientFoundDialog(Client client) { showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: const Text('Client existant trouvé'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Un client avec ces informations existe déjà :'), const SizedBox(height: 10), Text('Nom: ${client.nom} ${client.prenom}', style: const TextStyle(fontWeight: FontWeight.bold)), Text('Email: ${client.email}'), Text('Téléphone: ${client.telephone}'), if (client.adresse != null) Text('Adresse: ${client.adresse}'), const SizedBox(height: 10), const Text('Voulez-vous utiliser ces informations ?'), ], ), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); // Continuer avec les nouvelles données }, child: const Text('Non, créer nouveau'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _fillClientData(client); }, child: const Text('Oui, utiliser'), ), ], ), ); } // Valider et soumettre le formulaire void _submitForm() async { if (!_formKey.currentState!.validate()) return; try { setState(() => _isLoading = true); Client client; if (_selectedClient != null) { // Utiliser le client existant avec les données mises à jour client = Client( id: _selectedClient!.id, nom: _nomController.text.trim(), prenom: _prenomController.text.trim(), email: _emailController.text.trim().toLowerCase(), telephone: _telephoneController.text.trim(), adresse: _adresseController.text.trim().isEmpty ? null : _adresseController.text.trim(), dateCreation: _selectedClient!.dateCreation, actif: _selectedClient!.actif, ); } else { // Créer un nouveau client client = Client( nom: _nomController.text.trim(), prenom: _prenomController.text.trim(), email: _emailController.text.trim().toLowerCase(), telephone: _telephoneController.text.trim(), adresse: _adresseController.text.trim().isEmpty ? null : _adresseController.text.trim(), dateCreation: DateTime.now(), ); // Utiliser createOrGetClient pour éviter les doublons client = await _database.createOrGetClient(client); } widget.onClientSelected(client); } catch (e) { Get.snackbar( 'Erreur', 'Erreur lors de la sauvegarde du client: $e', backgroundColor: Colors.red, colorText: Colors.white, ); } finally { if (mounted) setState(() => _isLoading = false); } } @override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ // En-tête avec bouton de réinitialisation Row( children: [ const Text( 'Informations du client', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const Spacer(), if (_selectedClient != null) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.circular(12), ), child: const Text( 'Client existant', style: TextStyle(color: Colors.white, fontSize: 12), ), ), const SizedBox(width: 8), IconButton( onPressed: _clearForm, icon: const Icon(Icons.refresh), tooltip: 'Nouveau client', ), ], ), const SizedBox(height: 16), // Champs du formulaire Row( children: [ Expanded( child: TextFormField( controller: _nomController, decoration: const InputDecoration( labelText: 'Nom *', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Le nom est requis'; } return null; }, ), ), const SizedBox(width: 16), Expanded( child: TextFormField( controller: _prenomController, decoration: const InputDecoration( labelText: 'Prénom *', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Le prénom est requis'; } return null; }, ), ), ], ), const SizedBox(height: 16), // Email avec indicateur de chargement Stack( children: [ TextFormField( controller: _emailController, decoration: InputDecoration( labelText: 'Email *', border: const OutlineInputBorder(), suffixIcon: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : null, ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.trim().isEmpty) { return 'L\'email est requis'; } if (!GetUtils.isEmail(value)) { return 'Email invalide'; } return null; }, ), ], ), const SizedBox(height: 16), TextFormField( controller: _telephoneController, decoration: const InputDecoration( labelText: 'Téléphone *', border: OutlineInputBorder(), ), keyboardType: TextInputType.phone, validator: (value) { if (value == null || value.trim().isEmpty) { return 'Le téléphone est requis'; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _adresseController, decoration: const InputDecoration( labelText: 'Adresse', border: OutlineInputBorder(), ), maxLines: 2, ), // Suggestions if (_showSuggestions && _suggestions.isNotEmpty) ...[ const SizedBox(height: 16), Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), ), ), child: Row( children: [ const Icon(Icons.people, size: 16), const SizedBox(width: 8), const Text('Clients similaires trouvés:', style: TextStyle(fontWeight: FontWeight.bold)), const Spacer(), IconButton( onPressed: () => setState(() => _showSuggestions = false), icon: const Icon(Icons.close, size: 16), ), ], ), ), ...List.generate(_suggestions.length, (index) { final suggestion = _suggestions[index]; return ListTile( dense: true, leading: const Icon(Icons.person, size: 20), title: Text('${suggestion.nom} ${suggestion.prenom}'), subtitle: Text('${suggestion.email} • ${suggestion.telephone}'), trailing: ElevatedButton( onPressed: () => _fillClientData(suggestion), child: const Text('Utiliser'), ), ); }), ], ), ), ], const SizedBox(height: 24), // Bouton de soumission SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _isLoading ? null : _submitForm, child: _isLoading ? const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ), SizedBox(width: 8), Text('Traitement...'), ], ) : Text(_selectedClient != null ? 'Utiliser ce client' : 'Créer le client'), ), ), ], ), ); } }