import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:intl/intl.dart'; import '../../../providers/auth_provider.dart'; import '../../../providers/database_provider.dart'; import '../../../business/statistics_service.dart'; class StatisticsPage extends ConsumerStatefulWidget { const StatisticsPage({super.key}); @override ConsumerState createState() => _StatisticsPageState(); } class _StatisticsPageState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabCtrl; @override void initState() { super.initState(); _tabCtrl = TabController(length: 2, vsync: this); } @override void dispose() { _tabCtrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Statistiche'), bottom: TabBar( controller: _tabCtrl, tabs: const [ Tab(text: 'Andamento Mensile'), Tab(text: 'Top Clienti'), ], ), ), body: TabBarView( controller: _tabCtrl, children: [ _MonthlyChart(), _TopClientsChart(), ], ), ); } } class _MonthlyChart extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final agente = ref.watch(authProvider).agente; if (agente == null) return const Center(child: Text('Login richiesto')); final statsService = StatisticsService( ref.read(statisticheDaoProvider), ref.read(articoliDaoProvider), ref.read(clientiDaoProvider), ref.read(agentiDaoProvider), ); return FutureBuilder( future: statsService.getMonthlyTotals(agente.idAgente), builder: (_, snap) { if (!snap.hasData) return const Center(child: CircularProgressIndicator()); final data = snap.data!; if (data.isEmpty) return const Center(child: Text('Nessun dato statistico')); final sortedKeys = data.keys.toList()..sort(); final maxVal = data.values.reduce((a, b) => a > b ? a : b); return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Andamento Vendite', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 16), Expanded( child: BarChart( BarChartData( alignment: BarChartAlignment.spaceAround, maxY: maxVal * 1.2, barGroups: sortedKeys.asMap().entries.map((e) => BarChartGroupData( x: e.key, barRods: [BarChartRodData( toY: data[e.value]!, color: Theme.of(context).colorScheme.primary, width: 20, borderRadius: const BorderRadius.vertical(top: Radius.circular(4)), )], )).toList(), titlesData: FlTitlesData( bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, getTitlesWidget: (value, _) { final idx = value.toInt(); if (idx < 0 || idx >= sortedKeys.length) return const SizedBox(); final label = sortedKeys[idx]; return Text(label.length >= 7 ? label.substring(5, 7) : label, style: const TextStyle(fontSize: 10)); }, ), ), leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 60, getTitlesWidget: (value, _) => Text( NumberFormat.compact(locale: 'it').format(value), style: const TextStyle(fontSize: 10), ), ), ), topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), ), gridData: FlGridData(show: true, drawVerticalLine: false), borderData: FlBorderData(show: false), ), ), ), ], ), ); }, ); } } class _TopClientsChart extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final agente = ref.watch(authProvider).agente; if (agente == null) return const Center(child: Text('Login richiesto')); final statsService = StatisticsService( ref.read(statisticheDaoProvider), ref.read(articoliDaoProvider), ref.read(clientiDaoProvider), ref.read(agentiDaoProvider), ); return FutureBuilder( future: statsService.getTotalsByClient(agente.idAgente), builder: (_, snap) { if (!snap.hasData) return const Center(child: CircularProgressIndicator()); final data = snap.data!; if (data.isEmpty) return const Center(child: Text('Nessun dato')); final sorted = data.entries.toList()..sort((a, b) => b.value.compareTo(a.value)); final top5 = sorted.take(5).toList(); // final total = top5.fold(0.0, (s, e) => s + e.value); return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Top 5 Clienti per Fatturato', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 16), Expanded( child: PieChart( PieChartData( sections: top5.asMap().entries.map((e) => PieChartSectionData( value: e.value.value, title: '${e.key + 1}', color: _colors[e.key % _colors.length], radius: 60, titleStyle: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), )).toList(), sectionsSpace: 2, centerSpaceRadius: 40, ), ), ), const SizedBox(height: 16), ...top5.asMap().entries.map((e) => Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( children: [ Container(width: 12, height: 12, decoration: BoxDecoration(color: _colors[e.key % _colors.length], shape: BoxShape.circle)), const SizedBox(width: 8), Text('Cliente #${e.value.key}', style: Theme.of(context).textTheme.bodySmall), const Spacer(), Text(NumberFormat.currency(locale: 'it', symbol: '€').format(e.value.value), style: Theme.of(context).textTheme.bodySmall?.copyWith(fontWeight: FontWeight.bold)), ], ), )), ], ), ); }, ); } } const _colors = [ Colors.blue, Colors.red, Colors.green, Colors.orange, Colors.purple, Colors.teal, Colors.pink, Colors.indigo, ];