// lib/screens/savings_simulator_screen.dart import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:provider/provider.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:kzeduca_app/services/i18n_service.dart'; import 'package:kzeduca_app/services/firebase_service.dart'; import 'package:kzeduca_app/models/app_models.dart'; // KzEduca Palette const _kGradientStart = Color(0xFF512DA8); // Roxo vibrante const _kGradientEnd = Color(0xFF000000); // Preto profundo const _kAccent = Color(0xFF00BFA5); // Verde água const _kAction = Color(0xFFFFD600); // Amarelo/dourado const _kCardColor = Color(0x33FFFFFF); // Vidro fosco (opacidade de 20%) class SavingsSimulatorScreen extends StatefulWidget { const SavingsSimulatorScreen({super.key}); @override State createState() => _SavingsSimulatorScreenState(); } class _SavingsSimulatorScreenState extends State { final TextEditingController _initialValueController = TextEditingController(); final TextEditingController _monthlyDepositController = TextEditingController(); final TextEditingController _interestRateController = TextEditingController(); final TextEditingController _periodMonthsController = TextEditingController(); double? _result; bool _isLoading = false; String _error = ''; List _chartData = []; List _savedSimulations = []; @override void initState() { super.initState(); _loadSavedSimulations(); } @override void dispose() { _initialValueController.dispose(); _monthlyDepositController.dispose(); _interestRateController.dispose(); _periodMonthsController.dispose(); super.dispose(); } void _showAlertDialog(String message, {bool isError = false}) { final i18n = Provider.of(context, listen: false); showDialog( context: context, builder: (ctx) => AlertDialog( backgroundColor: Colors.grey[900], shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Text( isError ? i18n.t('error_prefix') : 'Info', style: GoogleFonts.montserrat(color: Colors.white, fontWeight: FontWeight.bold), ), content: Text( message, style: GoogleFonts.montserrat(color: Colors.white70), ), actions: [ TextButton( child: Text('Ok', style: GoogleFonts.montserrat(color: _kAccent)), onPressed: () { Navigator.of(ctx).pop(); }, ) ], ), ); } Future _loadSavedSimulations() async { final firebaseService = Provider.of(context, listen: false); final userId = FirebaseAuth.instance.currentUser?.uid; if (userId == null) return; firebaseService.streamSavedSimulations(userId).listen((snapshot) { if (mounted) { setState(() { _savedSimulations = snapshot.docs .map((doc) => SavingsSimulation.fromFirestore(doc)) .toList(); }); } }, onError: (error) { if (mounted) { _showAlertDialog("Erro ao carregar simulações salvas.", isError: true); } }); } void _simulateSavings() { final i18n = Provider.of(context, listen: false); setState(() { _error = ''; _isLoading = true; _result = null; _chartData = []; }); final initialValue = double.tryParse(_initialValueController.text); final monthlyDeposit = double.tryParse(_monthlyDepositController.text); final interestRate = double.tryParse(_interestRateController.text); final periodMonths = int.tryParse(_periodMonthsController.text); if (initialValue == null || monthlyDeposit == null || interestRate == null || periodMonths == null) { _showAlertDialog(i18n.t('fill_all_fields'), isError: true); setState(() { _isLoading = false; }); return; } if (initialValue < 0 || monthlyDeposit < 0 || interestRate < 0 || periodMonths <= 0) { _showAlertDialog(i18n.t('invalid_numeric_input'), isError: true); setState(() { _isLoading = false; }); return; } final monthlyInterestRate = interestRate / 100 / 12; double currentAmount = initialValue; List spots = [FlSpot(0, initialValue)]; for (int i = 0; i < periodMonths; i++) { currentAmount = (currentAmount + monthlyDeposit) * (1 + monthlyInterestRate); spots.add(FlSpot(i + 1.0, double.parse(currentAmount.toStringAsFixed(2)))); } setState(() { _result = double.parse(currentAmount.toStringAsFixed(2)); _chartData = spots; _isLoading = false; }); } Future _saveSimulation() async { final i18n = Provider.of(context, listen: false); final firebaseService = Provider.of(context, listen: false); final userId = FirebaseAuth.instance.currentUser?.uid; if (_result == null || userId == null) { _showAlertDialog(i18n.t('simulation_error'), isError: true); return; } setState(() { _isLoading = true; }); try { await firebaseService.saveSimulation(userId, { 'valorInicial': double.tryParse(_initialValueController.text) ?? 0.0, 'depositoMensal': double.tryParse(_monthlyDepositController.text) ?? 0.0, 'taxaJuros': double.tryParse(_interestRateController.text) ?? 0.0, 'periodoMeses': int.tryParse(_periodMonthsController.text) ?? 0, 'resultadoFinal': _result, 'simulationData': _chartData.map((spot) => {'x': spot.x.toInt(), 'y': spot.y}).toList(), 'timestamp': DateTime.now().toIso8601String(), }); _showAlertDialog(i18n.t('simulation_saved')); } catch (e) { _showAlertDialog(i18n.t('save_simulation_error'), isError: true); } finally { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { final i18n = Provider.of(context); return Scaffold( backgroundColor: Colors.black, body: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [_kGradientStart, _kGradientEnd], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Header Row( children: [ IconButton( icon: const Icon(Icons.arrow_back_rounded, color: Colors.white), onPressed: () => Navigator.pop(context), ), const SizedBox(width: 8), Flexible( child: Text( i18n.t('savings_simulator'), style: GoogleFonts.montserrat( color: const Color.fromARGB(255, 185, 185, 185), fontSize: 28, fontWeight: FontWeight.w700, ), overflow: TextOverflow.ellipsis, ), ), ], ), const SizedBox(height: 24), // Cartão Principal de Simulação _GlassCard( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( i18n.t('calculate_growth'), style: GoogleFonts.montserrat( fontSize: 18, color: Colors.white, fontWeight: FontWeight.w600, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), _buildInputField(i18n.t('initial_value'), _initialValueController, i18n: i18n), _buildInputField(i18n.t('monthly_deposit'), _monthlyDepositController, i18n: i18n), _buildInputField(i18n.t('annual_interest_rate'), _interestRateController, i18n: i18n), _buildInputField(i18n.t('period_months'), _periodMonthsController, i18n: i18n), const SizedBox(height: 24), ElevatedButton( onPressed: _isLoading ? null : _simulateSavings, style: ElevatedButton.styleFrom( backgroundColor: _kAccent, foregroundColor: Colors.black87, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), elevation: 8, shadowColor: _kAccent.withOpacity(0.5), ), child: _isLoading ? const SizedBox(height: 24, width: 24, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) : Text( i18n.t('simulate_savings'), style: GoogleFonts.montserrat(fontSize: 18, fontWeight: FontWeight.w600), ), ), ], ), ), if (_result != null) ...[ const SizedBox(height: 24), // Cartão de Resultado e Gráfico _GlassCard( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( i18n.t('estimated_final_value'), style: GoogleFonts.montserrat( fontSize: 18, color: Colors.white70, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( '${_result!.toStringAsFixed(2)} ${i18n.t('kwanza_symbol')}', style: GoogleFonts.montserrat( fontSize: 32, color: _kAction, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), AspectRatio( aspectRatio: 1.5, // Define uma proporção fixa, que é mais responsiva que uma altura fixa child: LineChart( _buildLineChartData(_chartData, i18n), ), ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: _isLoading ? null : _saveSimulation, icon: _isLoading ? const SizedBox.shrink() : const Icon(Icons.save_rounded, size: 20), label: _isLoading ? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) : Text(i18n.t('save_simulation'), style: GoogleFonts.montserrat(fontSize: 16, fontWeight: FontWeight.w600)), style: ElevatedButton.styleFrom( backgroundColor: _kAction, foregroundColor: Colors.black87, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 4, ), ), ], ), ), ], const SizedBox(height: 32), _buildSectionHeader(i18n.t('saved_simulations')), const SizedBox(height: 16), // Lista de Simulações Salvas _savedSimulations.isEmpty ? Text( i18n.t('no_simulations'), style: GoogleFonts.montserrat(color: Colors.white54, fontStyle: FontStyle.italic), textAlign: TextAlign.center, ) : ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _savedSimulations.length, itemBuilder: (context, index) { final sim = _savedSimulations[index]; return _SimulationResultCard( sim: sim, i18n: i18n, ); }, ), const SizedBox(height: 40), ], ), ), ), ), ); } LineChartData _buildLineChartData(List spots, I18nService i18n) { return LineChartData( gridData: FlGridData( show: true, drawVerticalLine: true, getDrawingHorizontalLine: (value) => FlLine(color: Colors.white12, strokeWidth: 1), getDrawingVerticalLine: (value) => FlLine(color: Colors.white12, strokeWidth: 1), ), titlesData: FlTitlesData( show: true, // CORREÇÃO: Usando a nova estrutura de `getTitlesWidget` (sem SideTitleWidget) bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 30, getTitlesWidget: (value, meta) { // Retorna o Widget Text diretamente com um Padding return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( 'Mês ${value.toInt()}', style: GoogleFonts.montserrat(fontSize: 10, color: Colors.white70), ), ); }, ), ), leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 40, getTitlesWidget: (value, meta) { // Retorna o Widget Text diretamente return Text( '${value.toInt()}', style: GoogleFonts.montserrat(fontSize: 10, color: Colors.white70), textAlign: TextAlign.right, ); }, ), ), topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)), ), borderData: FlBorderData( show: true, border: Border.all(color: Colors.white24, width: 1), ), lineBarsData: [ LineChartBarData( spots: spots, isCurved: true, color: _kAccent, barWidth: 4, isStrokeCapRound: true, dotData: FlDotData(show: true, getDotPainter: (spot, percent, barData, index) => FlDotCirclePainter(radius: 4, color: _kAccent, strokeWidth: 2, strokeColor: Colors.black)), belowBarData: BarAreaData( show: true, gradient: LinearGradient( colors: [_kAccent.withOpacity(0.5), _kAccent.withOpacity(0)], begin: Alignment.bottomCenter, end: Alignment.topCenter, ), ), ), ], ); } Widget _buildInputField(String label, TextEditingController controller, {required I18nService i18n}) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: GoogleFonts.montserrat( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white70, ), ), const SizedBox(height: 8), Container( decoration: BoxDecoration( color: _kCardColor, // Fundo transparente borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white24), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: TextFormField( controller: controller, keyboardType: TextInputType.number, style: GoogleFonts.montserrat(color: const Color.fromARGB(255, 0, 0, 0)), decoration: InputDecoration( hintText: 'Ex: 100', hintStyle: GoogleFonts.montserrat(color: const Color.fromARGB(137, 26, 25, 25)), border: InputBorder.none, // Remove a borda padrão contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ), ), ], ), ); } Widget _buildSectionHeader(String title) { return Column( children: [ const Divider(height: 20, thickness: 1.5, color: Colors.white12), const SizedBox(height: 16), Text( title, style: GoogleFonts.montserrat(fontSize: 22, fontWeight: FontWeight.bold, color: const Color.fromARGB(255, 255, 255, 255)), textAlign: TextAlign.center, ), const SizedBox(height: 8), ], ); } } class _GlassCard extends StatelessWidget { final Widget child; const _GlassCard({required this.child}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(24.0), decoration: BoxDecoration( color: _kCardColor, borderRadius: BorderRadius.circular(24.0), border: Border.all(color: const Color.fromARGB(255, 255, 255, 255).withOpacity(0.2)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.4), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: child, ); } } class _SimulationResultCard extends StatelessWidget { final SavingsSimulation sim; final I18nService i18n; const _SimulationResultCard({ required this.sim, required this.i18n, }); @override Widget build(BuildContext context) { return _GlassCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${i18n.t('estimated_final_value')}: ${sim.resultadoFinal.toStringAsFixed(2)} ${i18n.t('kwanza_symbol')}', style: GoogleFonts.montserrat(fontSize: 18, fontWeight: FontWeight.w600, color: _kAccent), ), const SizedBox(height: 12), Text( '${i18n.t('initial_value')}: ${sim.valorInicial.toStringAsFixed(2)} ${i18n.t('kwanza_symbol')}', style: GoogleFonts.montserrat(fontSize: 14, color: const Color.fromARGB(205, 255, 255, 255)), ), Text( '${i18n.t('monthly_deposit')}: ${sim.depositoMensal.toStringAsFixed(2)} ${i18n.t('kwanza_symbol')}', style: GoogleFonts.montserrat(fontSize: 14, color: Colors.white70), ), Text( '${i18n.t('annual_interest_rate')}: ${sim.taxaJuros.toStringAsFixed(1)}%', style: GoogleFonts.montserrat(fontSize: 14, color: Colors.white70), ), Text( '${i18n.t('period_months')}: ${sim.periodoMeses}', style: GoogleFonts.montserrat(fontSize: 14, color: Colors.white70), ), Text( 'Salvo em: ${DateTime.parse(sim.timestamp).toLocal().toString().split(' ')[0]}', style: GoogleFonts.montserrat(fontSize: 12, color: Colors.white54), ), ], ), ); } }