import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../../../core/di/injection.dart'; import '../../../../core/services/wave_integration_service.dart'; import '../../../../core/services/wave_payment_service.dart'; import '../../../../core/models/cotisation_model.dart'; import '../../../../shared/theme/app_theme.dart'; import '../../../../shared/widgets/buttons/primary_button.dart'; import '../../../../shared/widgets/common/unified_page_layout.dart'; /// Page de démonstration de l'intégration Wave Money /// Permet de tester toutes les fonctionnalités Wave class WaveDemoPage extends StatefulWidget { const WaveDemoPage({super.key}); @override State createState() => _WaveDemoPageState(); } class _WaveDemoPageState extends State with TickerProviderStateMixin { late WaveIntegrationService _waveIntegrationService; late WavePaymentService _wavePaymentService; late AnimationController _animationController; late Animation _fadeAnimation; final _amountController = TextEditingController(text: '5000'); final _phoneController = TextEditingController(text: '77123456'); final _nameController = TextEditingController(text: 'Test User'); bool _isLoading = false; String _lastResult = ''; WavePaymentStats? _stats; @override void initState() { super.initState(); _waveIntegrationService = getIt(); _wavePaymentService = getIt(); _animationController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeOut), ); _animationController.forward(); _loadStats(); } @override void dispose() { _amountController.dispose(); _phoneController.dispose(); _nameController.dispose(); _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return UnifiedPageLayout( title: 'Wave Money Demo', subtitle: 'Test d\'intégration Wave Money', showBackButton: true, child: FadeTransition( opacity: _fadeAnimation, child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildWaveHeader(), const SizedBox(height: 24), _buildTestForm(), const SizedBox(height: 24), _buildQuickActions(), const SizedBox(height: 24), _buildStatsSection(), const SizedBox(height: 24), _buildResultSection(), ], ), ), ), ); } Widget _buildWaveHeader() { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF00D4FF), Color(0xFF0099CC)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: const Color(0xFF00D4FF).withOpacity(0.3), blurRadius: 12, offset: const Offset(0, 4), ), ], ), child: Column( children: [ Row( children: [ Container( width: 60, height: 60, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), ), child: const Icon( Icons.waves, size: 32, color: Color(0xFF00D4FF), ), ), const SizedBox(width: 16), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Wave Money Integration', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), Text( 'Test et démonstration', style: TextStyle( fontSize: 14, color: Colors.white70, ), ), ], ), ), ], ), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: const Row( children: [ Icon(Icons.info_outline, color: Colors.white, size: 16), SizedBox(width: 8), Expanded( child: Text( 'Environnement de test - Aucun paiement réel ne sera effectué', style: TextStyle( fontSize: 12, color: Colors.white, ), ), ), ], ), ), ], ), ); } Widget _buildTestForm() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppTheme.borderLight), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Paramètres de test', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), const SizedBox(height: 16), // Montant TextFormField( controller: _amountController, keyboardType: TextInputType.number, decoration: const InputDecoration( labelText: 'Montant (XOF)', prefixIcon: Icon(Icons.attach_money), border: OutlineInputBorder(), ), ), const SizedBox(height: 16), // Numéro de téléphone TextFormField( controller: _phoneController, keyboardType: TextInputType.phone, decoration: const InputDecoration( labelText: 'Numéro Wave Money', prefixIcon: Icon(Icons.phone), prefixText: '+225 ', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), // Nom TextFormField( controller: _nameController, decoration: const InputDecoration( labelText: 'Nom du payeur', prefixIcon: Icon(Icons.person), border: OutlineInputBorder(), ), ), const SizedBox(height: 20), // Bouton de test SizedBox( width: double.infinity, child: PrimaryButton( text: _isLoading ? 'Test en cours...' : 'Tester le paiement Wave', icon: _isLoading ? null : Icons.play_arrow, onPressed: _isLoading ? null : _testWavePayment, isLoading: _isLoading, backgroundColor: const Color(0xFF00D4FF), ), ), ], ), ); } Widget _buildQuickActions() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppTheme.borderLight), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Actions rapides', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, children: [ _buildActionChip( 'Calculer frais', Icons.calculate, _calculateFees, ), _buildActionChip( 'Historique', Icons.history, _showHistory, ), _buildActionChip( 'Statistiques', Icons.analytics, _loadStats, ), _buildActionChip( 'Vider cache', Icons.clear_all, _clearCache, ), ], ), ], ), ); } Widget _buildActionChip(String label, IconData icon, VoidCallback onPressed) { return ActionChip( avatar: Icon(icon, size: 16), label: Text(label), onPressed: onPressed, backgroundColor: AppTheme.backgroundLight, side: const BorderSide(color: AppTheme.borderLight), ); } Widget _buildStatsSection() { if (_stats == null) { return const SizedBox.shrink(); } return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppTheme.borderLight), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Statistiques Wave Money', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), const SizedBox(height: 16), GridView.count( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), crossAxisCount: 2, childAspectRatio: 2.5, crossAxisSpacing: 12, mainAxisSpacing: 12, children: [ _buildStatCard( 'Total paiements', _stats!.totalPayments.toString(), Icons.payment, AppTheme.primaryColor, ), _buildStatCard( 'Réussis', _stats!.completedPayments.toString(), Icons.check_circle, AppTheme.successColor, ), _buildStatCard( 'Montant total', '${_stats!.totalAmount.toStringAsFixed(0)} XOF', Icons.attach_money, AppTheme.warningColor, ), _buildStatCard( 'Taux de réussite', '${_stats!.successRate.toStringAsFixed(1)}%', Icons.trending_up, AppTheme.infoColor, ), ], ), ], ), ); } Widget _buildStatCard(String title, String value, IconData icon, Color color) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: color.withOpacity(0.3)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: color, size: 16), const SizedBox(width: 4), Expanded( child: Text( title, style: TextStyle( fontSize: 12, color: color, fontWeight: FontWeight.w500, ), overflow: TextOverflow.ellipsis, ), ), ], ), const SizedBox(height: 4), Text( value, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: color, ), ), ], ), ); } Widget _buildResultSection() { if (_lastResult.isEmpty) { return const SizedBox.shrink(); } return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppTheme.borderLight), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Text( 'Dernier résultat', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), const Spacer(), IconButton( icon: const Icon(Icons.copy, size: 16), onPressed: () { Clipboard.setData(ClipboardData(text: _lastResult)); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Résultat copié')), ); }, tooltip: 'Copier', ), ], ), const SizedBox(height: 8), Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppTheme.backgroundLight, borderRadius: BorderRadius.circular(8), border: Border.all(color: AppTheme.borderLight), ), child: Text( _lastResult, style: const TextStyle( fontSize: 12, fontFamily: 'monospace', color: AppTheme.textSecondary, ), ), ), ], ), ); } // Actions Future _testWavePayment() async { setState(() { _isLoading = true; _lastResult = ''; }); try { final amount = double.tryParse(_amountController.text) ?? 0; if (amount <= 0) { throw Exception('Montant invalide'); } // Créer une cotisation de test final testCotisation = CotisationModel( id: 'test_${DateTime.now().millisecondsSinceEpoch}', numeroReference: 'TEST-${DateTime.now().millisecondsSinceEpoch}', membreId: 'test_member', nomMembre: _nameController.text, typeCotisation: 'MENSUELLE', montantDu: amount, montantPaye: 0, codeDevise: 'XOF', dateEcheance: DateTime.now().add(const Duration(days: 30)), statut: 'EN_ATTENTE', recurrente: false, nombreRappels: 0, annee: DateTime.now().year, dateCreation: DateTime.now(), ); // Initier le paiement Wave final result = await _waveIntegrationService.initiateWavePayment( cotisationId: testCotisation.id, montant: amount, numeroTelephone: _phoneController.text, nomPayeur: _nameController.text, metadata: { 'test_mode': true, 'demo_page': true, }, ); setState(() { _lastResult = ''' Test de paiement Wave Money Résultat: ${result.success ? 'SUCCÈS' : 'ÉCHEC'} ${result.success ? ''' ID Paiement: ${result.payment?.id} Session Wave: ${result.session?.waveSessionId} URL Checkout: ${result.checkoutUrl} Montant: ${amount.toStringAsFixed(0)} XOF Frais: ${_wavePaymentService.calculateWaveFees(amount).toStringAsFixed(0)} XOF ''' : ''' Erreur: ${result.errorMessage} '''} Timestamp: ${DateTime.now().toIso8601String()} '''.trim(); }); // Feedback haptique HapticFeedback.lightImpact(); // Recharger les statistiques await _loadStats(); } catch (e) { setState(() { _lastResult = 'Erreur lors du test: $e'; }); } finally { setState(() { _isLoading = false; }); } } void _calculateFees() { final amount = double.tryParse(_amountController.text) ?? 0; if (amount <= 0) { setState(() { _lastResult = 'Montant invalide pour le calcul des frais'; }); return; } final fees = _wavePaymentService.calculateWaveFees(amount); final total = amount + fees; setState(() { _lastResult = ''' Calcul des frais Wave Money Montant: ${amount.toStringAsFixed(0)} XOF Frais Wave: ${fees.toStringAsFixed(0)} XOF Total: ${total.toStringAsFixed(0)} XOF Barème Wave CI 2024: • 0-2000 XOF: Gratuit • 2001-10000 XOF: 25 XOF • 10001-50000 XOF: 100 XOF • 50001-100000 XOF: 200 XOF • 100001-500000 XOF: 500 XOF • >500000 XOF: 0.1% du montant '''.trim(); }); } Future _showHistory() async { try { final history = await _waveIntegrationService.getWavePaymentHistory(limit: 10); setState(() { _lastResult = ''' Historique des paiements Wave (10 derniers) ${history.isEmpty ? 'Aucun paiement trouvé' : history.map((payment) => ''' • ${payment.numeroReference} - ${payment.montant.toStringAsFixed(0)} XOF Statut: ${payment.statut} Date: ${payment.dateTransaction.toString().substring(0, 16)} ''').join('\n')} Total: ${history.length} paiement(s) '''.trim(); }); } catch (e) { setState(() { _lastResult = 'Erreur lors de la récupération de l\'historique: $e'; }); } } Future _loadStats() async { try { final stats = await _waveIntegrationService.getWavePaymentStats(); setState(() { _stats = stats; }); } catch (e) { print('Erreur lors du chargement des statistiques: $e'); } } Future _clearCache() async { try { // TODO: Implémenter le nettoyage du cache setState(() { _lastResult = 'Cache Wave Money vidé avec succès'; _stats = null; }); await _loadStats(); } catch (e) { setState(() { _lastResult = 'Erreur lors du nettoyage du cache: $e'; }); } } }