import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import 'package:fl_chart/fl_chart.dart'; import '../providers/factura_provider.dart'; import '../providers/configuracion_provider.dart'; class EstadisticasScreen extends StatefulWidget { const EstadisticasScreen({super.key}); @override State createState() => _EstadisticasScreenState(); } class _EstadisticasScreenState extends State { late int _year; @override void initState() { super.initState(); _year = DateTime.now().year; } @override Widget build(BuildContext context) { final facturaProv = context.watch(); final configProv = context.watch(); final moneda = configProv.config?.moneda ?? 'USD'; final symbol = moneda == 'USD' ? '\$' : moneda == 'EUR' ? '€' : moneda == 'MXN' ? 'MX\$' : '\$'; return Scaffold( appBar: AppBar(title: const Text('Estadísticas')), body: FutureBuilder( future: Future.wait([ facturaProv.gastoMensual(_year), facturaProv.gastosPorServicio(_year, DateTime.now().month), facturaProv.totalGastadoMes(_year, DateTime.now().month), ]), builder: (context, AsyncSnapshot> snapshot) { if (!snapshot.hasData) return const Center(child: CircularProgressIndicator()); final gastoMensual = snapshot.data![0] as List>; final gastoPorServicio = snapshot.data![1] as Map; final totalMes = snapshot.data![2] as double; return ListView( padding: const EdgeInsets.all(16), children: [ Text('Resumen $_year', style: Theme.of(context).textTheme.titleLarge), const SizedBox(height: 8), Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Gasto mensual actual', style: Theme.of(context).textTheme.titleSmall), Text('$symbol${NumberFormat('#,##0.00').format(totalMes)}', style: Theme.of(context).textTheme.headlineMedium), ], ), ), ), const SizedBox(height: 20), Text('Gasto mensual ($_year)', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), SizedBox( height: 200, child: BarChart( BarChartData( alignment: BarChartAlignment.spaceAround, maxY: (gastoMensual.isEmpty ? 1000 : gastoMensual.map((e) => (e['total'] as num).toDouble()).reduce((a, b) => a > b ? a : b)) * 1.2, barGroups: List.generate(12, (i) { final mes = (i + 1).toString().padLeft(2, '0'); final data = gastoMensual.where((e) => e['mes'] == mes).firstOrNull; return BarChartGroupData( x: i, barRods: [ BarChartRodData( toY: data != null ? (data['total'] as num).toDouble() : 0, color: Theme.of(context).colorScheme.primary, width: 16, borderRadius: const BorderRadius.vertical(top: Radius.circular(4)), ), ], ); }), titlesData: FlTitlesData( leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 40, getTitlesWidget: (v, _) => Text('$symbol${v.toInt()}', style: const TextStyle(fontSize: 10)))), bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, getTitlesWidget: (v, _) { const meses = ['E', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']; return Text(meses[v.toInt()], style: const TextStyle(fontSize: 10)); })), rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), ), gridData: FlGridData(show: true, drawVerticalLine: false, horizontalInterval: (gastoMensual.isEmpty ? 1000 : gastoMensual.map((e) => (e['total'] as num).toDouble()).reduce((a, b) => a > b ? a : b)) / 4), borderData: FlBorderData(show: false), ), ), ), const SizedBox(height: 20), Text('Distribución por servicio', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), if (gastoPorServicio.isEmpty) Card(child: Padding(padding: const EdgeInsets.all(16), child: Text('Sin datos este mes'))) else Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( children: gastoPorServicio.entries.map((e) { final total = gastoPorServicio.values.fold(0.0, (a, b) => a + b); final pct = total > 0 ? e.value / total * 100 : 0.0; return Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( children: [ SizedBox(width: 100, child: Text(e.key, style: const TextStyle(fontSize: 13))), Expanded( child: ClipRRect( borderRadius: BorderRadius.circular(4), child: LinearProgressIndicator( value: pct / 100, backgroundColor: Colors.grey[200], minHeight: 12, ), ), ), const SizedBox(width: 8), SizedBox(width: 70, child: Text('$symbol${NumberFormat('#,##0.00').format(e.value)}', style: const TextStyle(fontSize: 12), textAlign: TextAlign.right)), ], ), ); }).toList(), ), ), ), ], ); }, ), ); } }