import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:intl/intl.dart'; import '../../core/utils/snackbar_util.dart'; /// Dynamic Chit Fund Calculator with adjustable parameters class DynamicChitCalculator extends StatefulWidget { final double chitValue; final int durationMonths; final double subscriptionAmount; final double commissionAmount; final ValueChanged>? onCalculationsChanged; const DynamicChitCalculator({ super.key, required this.chitValue, required this.durationMonths, required this.subscriptionAmount, required this.commissionAmount, this.onCalculationsChanged, }); @override State createState() => _DynamicChitCalculatorState(); } class _DynamicChitCalculatorState extends State { // Adjustable parameters double _startingPercentage = 87.65; // First month lifter gets 87.65% double _endingPercentage = 112.35; // Last month lifter gets 112.35% (more than chit value!) String _calculationMode = 'linear'; // linear, custom, accelerated @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Calculator controls _buildCalculatorControls(), SizedBox(height: 16.h), // Month-wise table _buildCompleteScheduleTable(), SizedBox(height: 16.h), // Summary & insights _buildSummaryCard(), ], ); } Widget _buildCalculatorControls() { return Card( elevation: 0, color: Colors.blue.shade50, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), side: BorderSide(color: Colors.blue.shade200), ), child: ExpansionTile( leading: Icon(Icons.tune, color: Colors.blue.shade700), title: Text( 'Adjust Lift Amount Calculations', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.blue.shade800, ), ), subtitle: Text( 'Customize how much lifters get each month', style: TextStyle(fontSize: 12.sp), ), children: [ Padding( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Starting percentage Text( 'First Month Lifter Gets:', style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), SizedBox(height: 8.h), Row( children: [ Expanded( child: Slider( value: _startingPercentage, min: 70, max: 95, divisions: 50, label: '${_startingPercentage.toStringAsFixed(1)}%', activeColor: Colors.green.shade600, onChanged: (value) { setState(() { _startingPercentage = value; _notifyChanges(); }); }, ), ), SizedBox( width: 100.w, child: Text( '${_startingPercentage.toStringAsFixed(1)}% = ₹${_calculateLiftAmount(1).toStringAsFixed(0)}', style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w600, color: Colors.green.shade700, ), textAlign: TextAlign.right, ), ), ], ), SizedBox(height: 16.h), // Ending percentage Text( 'Last Month Lifter Gets:', style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), SizedBox(height: 8.h), Row( children: [ Expanded( child: Slider( value: _endingPercentage, min: 95, max: 120, divisions: 50, label: '${_endingPercentage.toStringAsFixed(1)}%', activeColor: Colors.purple.shade600, onChanged: (value) { setState(() { _endingPercentage = value; _notifyChanges(); }); }, ), ), SizedBox( width: 100.w, child: Text( '${_endingPercentage.toStringAsFixed(1)}% = ₹${_calculateLiftAmount(widget.durationMonths).toStringAsFixed(0)}', style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w600, color: Colors.purple.shade700, ), textAlign: TextAlign.right, ), ), ], ), SizedBox(height: 16.h), // Calculation mode Text( 'Progression Mode:', style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), SizedBox(height: 8.h), Wrap( spacing: 8.w, children: [ ChoiceChip( label: const Text('Linear'), selected: _calculationMode == 'linear', onSelected: (selected) { if (selected) { setState(() { _calculationMode = 'linear'; _notifyChanges(); }); } }, selectedColor: Colors.green.shade200, ), ChoiceChip( label: const Text('Accelerated'), selected: _calculationMode == 'accelerated', onSelected: (selected) { if (selected) { setState(() { _calculationMode = 'accelerated'; _notifyChanges(); }); } }, selectedColor: Colors.orange.shade200, ), ChoiceChip( label: const Text('Custom'), selected: _calculationMode == 'custom', onSelected: (selected) { if (selected) { setState(() { _calculationMode = 'custom'; _notifyChanges(); }); } }, selectedColor: Colors.purple.shade200, ), ], ), SizedBox(height: 12.h), // Preset buttons Wrap( spacing: 8.w, runSpacing: 8.h, children: [ OutlinedButton.icon( onPressed: () => _applyPreset('conservative'), icon: Icon(Icons.shield, size: 16.w), label: const Text('Conservative'), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), ), ), OutlinedButton.icon( onPressed: () => _applyPreset('balanced'), icon: Icon(Icons.balance, size: 16.w), label: const Text('Balanced'), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), ), ), OutlinedButton.icon( onPressed: () => _applyPreset('aggressive'), icon: Icon(Icons.trending_up, size: 16.w), label: const Text('Aggressive'), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), ), ), OutlinedButton.icon( onPressed: () => _applyPreset('sample'), icon: Icon(Icons.file_copy, size: 16.w), label: const Text('Your Sample'), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), ), ), ], ), ], ), ), ], ), ); } Widget _buildCompleteScheduleTable() { return Card( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Container( constraints: BoxConstraints(minWidth: MediaQuery.of(context).size.width - 32.w), child: SingleChildScrollView( child: DataTable( headingRowHeight: 56.h, headingRowColor: MaterialStateProperty.all(Colors.green.shade600), columnSpacing: 12.w, horizontalMargin: 12.w, dataRowMinHeight: 48.h, dataRowMaxHeight: 56.h, columns: [ _buildColumn('Month'), _buildColumn('Chit\nValue'), _buildColumn('Lifter\nGets', tooltip: 'Net amount paid to lifter'), _buildColumn('Sub.', tooltip: 'Monthly subscription'), _buildColumn('Fee'), _buildColumn('Total\nPayment'), _buildColumn('Dividend', tooltip: 'Chit Value - Lift Amount'), ], rows: List.generate(widget.durationMonths, (index) { return _buildDataRow(index + 1); }), ), ), ), ), ); } DataColumn _buildColumn(String label, {String? tooltip}) { return DataColumn( label: Tooltip( message: tooltip ?? label, child: Text( label, style: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, ), ), ); } DataRow _buildDataRow(int month) { final monthDate = _getMonthDate(month); final liftAmount = _calculateLiftAmount(month); final dividendAmount = widget.chitValue - liftAmount; final totalPayment = widget.subscriptionAmount + widget.commissionAmount; final isEarly = month <= (widget.durationMonths * 0.3).ceil(); final isLast = month == widget.durationMonths; final rowColor = isLast ? Colors.purple.shade50 : isEarly ? Colors.green.shade50 : null; return DataRow( color: MaterialStateProperty.all(rowColor), cells: [ _buildCell('$month\n$monthDate', isHeader: true), _buildCell('₹${widget.chitValue.toStringAsFixed(0)}'), _buildCell( '₹${liftAmount.toStringAsFixed(0)}', color: Colors.green.shade700, bold: true, ), _buildCell('₹${widget.subscriptionAmount.toStringAsFixed(0)}'), _buildCell('₹${widget.commissionAmount.toStringAsFixed(0)}'), _buildCell( '₹${totalPayment.toStringAsFixed(0)}', bold: true, ), _buildCell( '${dividendAmount >= 0 ? "+" : ""}₹${dividendAmount.toStringAsFixed(0)}', color: dividendAmount >= 0 ? Colors.blue.shade700 : Colors.red.shade700, bold: true, ), ], ); } DataCell _buildCell(String text, {bool isHeader = false, Color? color, bool bold = false}) { return DataCell( Text( text, style: TextStyle( fontSize: isHeader ? 11.sp : 12.sp, fontWeight: bold || isHeader ? FontWeight.w600 : FontWeight.normal, color: color ?? Colors.grey.shade800, ), textAlign: TextAlign.center, ), ); } Widget _buildSummaryCard() { final totalPayment = widget.subscriptionAmount + widget.commissionAmount; final totalPerMember = totalPayment * widget.durationMonths; final firstMonthLift = _calculateLiftAmount(1); final lastMonthLift = _calculateLiftAmount(widget.durationMonths); final firstMonthDividend = widget.chitValue - firstMonthLift; final lastMonthDividend = widget.chitValue - lastMonthLift; return Card( elevation: 0, color: Colors.orange.shade50, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), side: BorderSide(color: Colors.orange.shade200), ), child: Padding( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.analytics, color: Colors.orange.shade700, size: 18.w), SizedBox(width: 8.w), Text( 'Chitfund Analysis', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, color: Colors.orange.shade800, ), ), ], ), SizedBox(height: 12.h), // Key metrics Row( children: [ Expanded( child: _buildMetricCard( 'First Month', 'Lifter: ₹${firstMonthLift.toStringAsFixed(0)}', 'Dividend: +₹${firstMonthDividend.toStringAsFixed(0)}', Colors.green.shade600, Icons.rocket_launch, ), ), SizedBox(width: 12.w), Expanded( child: _buildMetricCard( 'Last Month', 'Lifter: ₹${lastMonthLift.toStringAsFixed(0)}', 'Dividend: ${lastMonthDividend >= 0 ? "+" : ""}₹${lastMonthDividend.toStringAsFixed(0)}', Colors.purple.shade600, Icons.flag, ), ), ], ), SizedBox(height: 12.h), Divider(color: Colors.orange.shade300), SizedBox(height: 8.h), _buildSummaryRow('Chit Amount', '₹${widget.chitValue.toStringAsFixed(0)}'), _buildSummaryRow('Monthly Installment (Fixed)', '₹${totalPayment.toStringAsFixed(0)}'), _buildSummaryRow('Total per Member', '₹${totalPerMember.toStringAsFixed(0)}'), _buildSummaryRow( 'Lift Amount Range', '₹${firstMonthLift.toStringAsFixed(0)} → ₹${lastMonthLift.toStringAsFixed(0)}', ), _buildSummaryRow( 'Monthly Increment', '₹${_calculateMonthlyIncrement().toStringAsFixed(0)}', ), ], ), ), ); } Widget _buildMetricCard(String title, String value1, String value2, Color color, IconData icon) { return Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8.r), border: Border.all(color: color.withOpacity(0.3)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: color, size: 16.w), SizedBox(width: 6.w), Expanded( child: Text( title, style: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.w600, color: color, ), ), ), ], ), SizedBox(height: 6.h), Text( value1, style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.bold, color: Colors.grey.shade800, ), ), Text( value2, style: TextStyle( fontSize: 11.sp, color: Colors.grey.shade700, ), ), ], ), ); } Widget _buildSummaryRow(String label, String value) { return Padding( padding: EdgeInsets.symmetric(vertical: 4.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade700, ), ), Text( value, style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), ], ), ); } /// Calculate lift amount for a specific month double _calculateLiftAmount(int month) { if (widget.durationMonths <= 1) return widget.chitValue; final double startPercentage = _startingPercentage / 100; final double endPercentage = _endingPercentage / 100; double percentage; switch (_calculationMode) { case 'linear': // Linear progression final double incrementPerMonth = (endPercentage - startPercentage) / (widget.durationMonths - 1); percentage = startPercentage + (incrementPerMonth * (month - 1)); break; case 'accelerated': // Accelerated - grows faster in later months final double progress = (month - 1) / (widget.durationMonths - 1); final double accelerationFactor = progress * progress; // Quadratic percentage = startPercentage + ((endPercentage - startPercentage) * accelerationFactor); break; case 'custom': // Custom - could add more complex formulas here final double incrementPerMonth = (endPercentage - startPercentage) / (widget.durationMonths - 1); percentage = startPercentage + (incrementPerMonth * (month - 1)); break; default: percentage = startPercentage; } return widget.chitValue * percentage; } double _calculateMonthlyIncrement() { if (widget.durationMonths <= 1) return 0; final first = _calculateLiftAmount(1); final second = _calculateLiftAmount(2); return second - first; } String _getMonthDate(int monthNumber) { final now = DateTime.now(); final futureMonth = DateTime(now.year, now.month + monthNumber - 1); return DateFormat('MMM-yy').format(futureMonth); } void _applyPreset(String preset) { setState(() { switch (preset) { case 'conservative': _startingPercentage = 90.0; _endingPercentage = 100.0; _calculationMode = 'linear'; break; case 'balanced': _startingPercentage = 85.0; _endingPercentage = 105.0; _calculationMode = 'linear'; break; case 'aggressive': _startingPercentage = 80.0; _endingPercentage = 115.0; _calculationMode = 'accelerated'; break; case 'sample': // Match your exact sample data _startingPercentage = 87.65; _endingPercentage = 112.35; _calculationMode = 'linear'; break; } _notifyChanges(); }); SnackbarUtil.showSuccess('Preset "$preset" applied!'); } void _notifyChanges() { if (widget.onCalculationsChanged != null) { widget.onCalculationsChanged!({ 'startingPercentage': _startingPercentage, 'endingPercentage': _endingPercentage, 'calculationMode': _calculationMode, 'firstMonthLift': _calculateLiftAmount(1), 'lastMonthLift': _calculateLiftAmount(widget.durationMonths), }); } } }