import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../core/services/chit_group_service.dart'; import '../../core/utils/chit_calculator.dart'; import '../../core/utils/snackbar_util.dart'; import '../../shared/widgets/monthly_schedule_table.dart'; class CreateGroupDialog extends StatefulWidget { const CreateGroupDialog({super.key}); @override State createState() => _CreateGroupDialogState(); } class _CreateGroupDialogState extends State { final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _totalValueController = TextEditingController(); final _monthlyInstallmentController = TextEditingController(); final _durationMonthsController = TextEditingController(); final _maxMembersController = TextEditingController(); final _foremanCommissionController = TextEditingController(); final _foremanCommissionTypeController = TextEditingController(); final _maxDividendController = TextEditingController(); final _drawDateController = TextEditingController(); bool _isLoading = false; String? _selectedDrawDate; @override void initState() { super.initState(); _drawDateController.text = '15'; // Default draw date _foremanCommissionController.text = '250'; // Default commission _foremanCommissionTypeController.text = 'fixed'; // Default commission type _maxDividendController.text = '500'; // Default max dividend } @override void dispose() { _nameController.dispose(); _totalValueController.dispose(); _monthlyInstallmentController.dispose(); _durationMonthsController.dispose(); _maxMembersController.dispose(); _foremanCommissionController.dispose(); _foremanCommissionTypeController.dispose(); _maxDividendController.dispose(); _drawDateController.dispose(); super.dispose(); } void _calculateMonthlyInstallment() { final totalValue = double.tryParse(_totalValueController.text); final durationMonths = int.tryParse(_durationMonthsController.text); final commissionType = _foremanCommissionTypeController.text; if (totalValue != null && durationMonths != null) { double commission; if (commissionType == 'percentage') { final rate = double.tryParse(_foremanCommissionController.text) ?? 5.0; commission = (totalValue / durationMonths) * (rate / 100); } else { commission = double.tryParse(_foremanCommissionController.text) ?? 250.0; } // Generic formula: Monthly Installment = (Total Value ÷ Duration Months) + Commission final subscriptionPerMonth = totalValue / durationMonths; final monthlyInstallment = subscriptionPerMonth + commission; _monthlyInstallmentController.text = monthlyInstallment.toStringAsFixed(0); } setState(() {}); // Rebuild to update schedule } void _calculateTotalValue() { final monthlyInstallment = double.tryParse(_monthlyInstallmentController.text); final durationMonths = int.tryParse(_durationMonthsController.text); final commissionType = _foremanCommissionTypeController.text; if (monthlyInstallment != null && durationMonths != null) { double totalValue; if (commissionType == 'percentage') { // For percentage commission: total_value = monthly_installment * duration_months / (1 + rate/100) final rate = double.tryParse(_foremanCommissionController.text) ?? 5.0; totalValue = (monthlyInstallment * durationMonths) / (1 + rate/100); } else { // For fixed commission: total_value = (monthly_installment - commission) × duration_months final commission = double.tryParse(_foremanCommissionController.text) ?? 250.0; totalValue = (monthlyInstallment - commission) * durationMonths; } _totalValueController.text = totalValue.toStringAsFixed(0); } setState(() {}); // Rebuild to update schedule } // Calculate advantage structure using the generic formula Map _calculateAdvantageStructure() { final totalValue = double.tryParse(_totalValueController.text) ?? 0; final durationMonths = int.tryParse(_durationMonthsController.text) ?? 0; final commissionType = _foremanCommissionTypeController.text; final commission = double.tryParse(_foremanCommissionController.text) ?? 250; final maxDividend = double.tryParse(_maxDividendController.text) ?? (commission * 2); if (totalValue <= 0 || durationMonths <= 0) { return {}; } // Use the generic calculator final advantageStructure = ChitCalculator.calculateAdvantageStructure( chitValue: totalValue, months: durationMonths, commissionPerMonth: commission, maxDividend: maxDividend, ); return { 'first_month': { 'payment': advantageStructure['first_month_winner']['installment_paid'], 'receipt': advantageStructure['first_month_winner']['bid_amount'], 'net_gain': advantageStructure['first_month_winner']['net_gain'], 'dividend_per_member': advantageStructure['first_month_winner']['dividend_others_get'], }, 'last_month': { 'payment': advantageStructure['last_month_winner']['total_paid'], 'receipt': advantageStructure['last_month_winner']['total_received'], 'net_gain': advantageStructure['last_month_winner']['net_gain_total'], 'dividend_per_member': advantageStructure['last_month_winner']['dividend_others_pay'] * -1, }, 'monthly_commission': advantageStructure['commission_per_month'], 'winner_payout': advantageStructure['first_month_winner']['bid_amount'], 'dividend_per_member_early': advantageStructure['first_month_winner']['dividend_others_get'], 'subscription_per_month': advantageStructure['subscription_per_month'], 'installment_per_month': advantageStructure['installment_per_month'], }; } Future _createGroup() async { if (!_formKey.currentState!.validate()) return; setState(() => _isLoading = true); try { final groupData = { 'name': _nameController.text.trim(), 'total_value': double.parse(_totalValueController.text), 'monthly_installment': double.parse(_monthlyInstallmentController.text), 'duration_months': int.parse(_durationMonthsController.text), 'max_members': int.parse(_maxMembersController.text), 'foreman_commission_amount': double.parse(_foremanCommissionController.text), 'foreman_commission_type': _foremanCommissionTypeController.text, if (_foremanCommissionTypeController.text == 'percentage') 'foreman_commission_rate': double.parse(_foremanCommissionController.text), 'draw_date': int.parse(_drawDateController.text), }; final success = await ChitGroupService.to.createChitGroup(groupData); if (success) { Navigator.of(context).pop(); // Close dialog SnackbarUtil.showSuccess( 'Chit group created successfully!', title: 'Success', ); } } catch (e) { SnackbarUtil.showError( 'Failed to create chit group. Please try again.', title: 'Error', ); } finally { setState(() => _isLoading = false); } } @override Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)), child: Container( width: MediaQuery.of(context).size.width > 600 ? 600.w : double.infinity, constraints: BoxConstraints( maxHeight: 0.85.sh, maxWidth: MediaQuery.of(context).size.width * 0.95, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Header Container( padding: EdgeInsets.all(20.w), decoration: BoxDecoration( color: Colors.green.shade600, borderRadius: BorderRadius.only( topLeft: Radius.circular(16.r), topRight: Radius.circular(16.r), ), ), child: Row( children: [ Icon( Icons.group_add, color: Colors.white, size: 24.w, ), SizedBox(width: 12.w), Text( 'Create New Chitfund', style: TextStyle( color: Colors.white, fontSize: 18.sp, fontWeight: FontWeight.w600, ), ), const Spacer(), IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.close, color: Colors.white), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), ], ), ), // Form Content Flexible( child: SingleChildScrollView( padding: EdgeInsets.all(20.w), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Basic Information Section _buildSectionTitle('Basic Information'), SizedBox(height: 16.h), TextFormField( controller: _nameController, decoration: InputDecoration( labelText: 'Chitfund Name', hintText: 'Enter chitfund name', prefixIcon: const Icon(Icons.group), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), validator: (value) { if (value == null || value.trim().isEmpty) { return 'Chitfund name is required'; } if (value.trim().length < 3) { return 'Chitfund name must be at least 3 characters'; } return null; }, ), SizedBox(height: 16.h), // Financial Details Section _buildSectionTitle('Chitfund Details'), SizedBox(height: 16.h), Row( children: [ Expanded( child: TextFormField( controller: _totalValueController, decoration: InputDecoration( labelText: 'Total Value (₹)', hintText: 'e.g., 100000', prefixIcon: const Icon(Icons.currency_rupee), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, onChanged: (_) => _calculateMonthlyInstallment(), validator: (value) { if (value == null || value.isEmpty) { return 'Total value is required'; } final amount = double.tryParse(value); if (amount == null || amount <= 0) { return 'Please enter a valid amount'; } if (amount < 1000) { return 'Minimum amount is ₹1,000'; } return null; }, ), ), SizedBox(width: 16.w), Expanded( child: TextFormField( controller: _monthlyInstallmentController, decoration: InputDecoration( labelText: 'Monthly Installment (₹)', hintText: 'e.g., 5000', prefixIcon: const Icon(Icons.payment), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, onChanged: (_) => _calculateTotalValue(), validator: (value) { if (value == null || value.isEmpty) { return 'Monthly installment is required'; } final amount = double.tryParse(value); if (amount == null || amount <= 0) { return 'Please enter a valid amount'; } if (amount < 100) { return 'Minimum installment is ₹100'; } return null; }, ), ), ], ), SizedBox(height: 16.h), Row( children: [ Expanded( child: TextFormField( controller: _durationMonthsController, decoration: InputDecoration( labelText: 'Duration (Months)', hintText: 'e.g., 20', prefixIcon: const Icon(Icons.calendar_today), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, onChanged: (_) => _calculateMonthlyInstallment(), validator: (value) { if (value == null || value.isEmpty) { return 'Duration is required'; } final months = int.tryParse(value); if (months == null || months < 6) { return 'Minimum duration is 6 months'; } if (months > 60) { return 'Maximum duration is 60 months'; } return null; }, ), ), SizedBox(width: 16.w), Expanded( child: TextFormField( controller: _maxMembersController, decoration: InputDecoration( labelText: 'Maximum Members', hintText: 'e.g., 20', prefixIcon: const Icon(Icons.people), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, validator: (value) { if (value == null || value.isEmpty) { return 'Maximum members is required'; } final members = int.tryParse(value); if (members == null || members < 2) { return 'Minimum 2 members required'; } if (members > 100) { return 'Maximum 100 members allowed'; } return null; }, ), ), ], ), SizedBox(height: 16.h), Row( children: [ Expanded( child: TextFormField( controller: _foremanCommissionController, decoration: InputDecoration( labelText: _foremanCommissionTypeController.text == 'percentage' ? 'Foreman Commission Rate (%)' : 'Foreman Commission (₹)', hintText: _foremanCommissionTypeController.text == 'percentage' ? 'e.g., 5' : 'e.g., 250', prefixIcon: Icon( _foremanCommissionTypeController.text == 'percentage' ? Icons.percent : Icons.currency_rupee, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, onChanged: (_) => _calculateMonthlyInstallment(), validator: (value) { if (value == null || value.isEmpty) { return _foremanCommissionTypeController.text == 'percentage' ? 'Commission rate is required' : 'Commission is required'; } final commission = double.tryParse(value); if (commission == null || commission < 0) { return 'Please enter a valid value'; } if (_foremanCommissionTypeController.text == 'percentage' && commission > 100) { return 'Commission rate cannot exceed 100%'; } return null; }, ), ), SizedBox(width: 16.w), Expanded( child: DropdownButtonFormField( value: _foremanCommissionTypeController.text, decoration: InputDecoration( labelText: 'Commission Type', prefixIcon: const Icon(Icons.settings), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), items: const [ DropdownMenuItem(value: 'fixed', child: Text('Fixed Amount')), DropdownMenuItem(value: 'percentage', child: Text('Percentage')), ], onChanged: (value) { if (value != null) { _foremanCommissionTypeController.text = value; // Update the commission field value based on type if (value == 'percentage') { _foremanCommissionController.text = '5'; // Default 5% } else { _foremanCommissionController.text = '250'; // Default ₹250 } _calculateMonthlyInstallment(); setState(() {}); // Trigger rebuild to update UI } }, ), ), ], ), SizedBox(height: 16.h), Row( children: [ Expanded( child: TextFormField( controller: _maxDividendController, decoration: InputDecoration( labelText: 'Max Dividend (₹)', hintText: 'e.g., 500', prefixIcon: const Icon(Icons.trending_up), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, validator: (value) { if (value == null || value.isEmpty) { return 'Max dividend is required'; } final maxDividend = double.tryParse(value); if (maxDividend == null || maxDividend < 0) { return 'Please enter a valid amount'; } return null; }, ), ), SizedBox(width: 16.w), Expanded(child: Container()), // Empty space for alignment ], ), SizedBox(height: 16.h), Row( children: [ Expanded( child: TextFormField( controller: _drawDateController, decoration: InputDecoration( labelText: 'Draw Date (Day of Month)', hintText: 'e.g., 15', prefixIcon: const Icon(Icons.casino), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), ), ), keyboardType: TextInputType.number, validator: (value) { if (value == null || value.isEmpty) { return 'Draw date is required'; } final day = int.tryParse(value); if (day == null || day < 1 || day > 31) { return 'Please enter a valid day (1-31)'; } return null; }, ), ), SizedBox(width: 16.w), Expanded(child: Container()), // Empty space for alignment ], ), SizedBox(height: 24.h), // Summary Section _buildSectionTitle('Summary'), SizedBox(height: 16.h), Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.grey.shade300), ), child: Column( children: [ _buildSummaryRow('Chitfund Name', _nameController.text.isEmpty ? 'Not set' : _nameController.text), _buildSummaryRow('Total Value', _totalValueController.text.isEmpty ? 'Not set' : '₹${_totalValueController.text}'), _buildSummaryRow('Monthly Installment', _monthlyInstallmentController.text.isEmpty ? 'Not set' : '₹${_monthlyInstallmentController.text}'), _buildSummaryRow('Duration', _durationMonthsController.text.isEmpty ? 'Not set' : '${_durationMonthsController.text} months'), _buildSummaryRow('Max Members', _maxMembersController.text.isEmpty ? 'Not set' : _maxMembersController.text), _buildSummaryRow('Commission', _foremanCommissionController.text.isEmpty ? 'Not set' : '₹${_foremanCommissionController.text}'), _buildSummaryRow('Max Dividend', _maxDividendController.text.isEmpty ? 'Not set' : '₹${_maxDividendController.text}'), _buildSummaryRow('Draw Date', _drawDateController.text.isEmpty ? 'Not set' : '${_drawDateController.text}th of each month'), ], ), ), SizedBox(height: 24.h), // Advantage Structure Section _buildSectionTitle('Advantage Structure'), SizedBox(height: 16.h), _buildAdvantageStructureCard(), SizedBox(height: 24.h), // Monthly Schedule Section _buildSectionTitle('Month-wise Payment Schedule'), SizedBox(height: 16.h), ExpandableMonthlySchedule( totalValue: double.tryParse(_totalValueController.text) ?? 0, durationMonths: int.tryParse(_durationMonthsController.text) ?? 0, monthlyInstallment: double.tryParse(_monthlyInstallmentController.text) ?? 0, commission: double.tryParse(_foremanCommissionController.text) ?? 0, maxDividend: double.tryParse(_maxDividendController.text) ?? 0, ), SizedBox(height: 24.h), // Action Buttons Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.of(context).pop(), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), ), child: Text( 'Cancel', style: TextStyle(fontSize: 16.sp), ), ), ), SizedBox(width: 16.w), Expanded( child: ElevatedButton( onPressed: _isLoading ? null : _createGroup, style: ElevatedButton.styleFrom( backgroundColor: Colors.green.shade600, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 16.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), ), child: _isLoading ? SizedBox( height: 20.h, width: 20.w, child: const CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text( 'Create Chitfund', style: TextStyle(fontSize: 16.sp), ), ), ), ], ), ], ), ), ), ), ], ), ), ); } Widget _buildSectionTitle(String title) { return Text( title, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ); } 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: 14.sp, color: Colors.grey.shade600, ), ), Text( value, style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, color: Colors.grey.shade800, ), ), ], ), ); } Widget _buildAdvantageStructureCard() { final advantageData = _calculateAdvantageStructure(); if (advantageData.isEmpty) { return Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.orange.shade200), ), child: Row( children: [ Icon(Icons.info_outline, color: Colors.orange.shade600, size: 20.w), SizedBox(width: 8.w), Expanded( child: Text( 'Fill in the group details above to see the advantage structure', style: TextStyle( fontSize: 14.sp, color: Colors.orange.shade700, ), ), ), ], ), ); } return Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.blue.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.trending_up, color: Colors.blue.shade600, size: 20.w), SizedBox(width: 8.w), Text( 'Chit Fund Advantage Structure', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: Colors.blue.shade800, ), ), ], ), SizedBox(height: 16.h), // First Month Winner Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: Colors.green.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.green.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.rocket_launch, color: Colors.green.shade600, size: 16.w), SizedBox(width: 8.w), Text( 'First Month Winner (Early Advantage)', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.green.shade700, ), ), ], ), SizedBox(height: 8.h), _buildAdvantageRow('Monthly Payment', '₹${advantageData['first_month']['payment'].toStringAsFixed(0)}'), _buildAdvantageRow('Bid Amount', '₹${advantageData['first_month']['receipt'].toStringAsFixed(0)}'), _buildAdvantageRow('Net Gain', '₹${advantageData['first_month']['net_gain'].toStringAsFixed(0)}', isHighlight: true), _buildAdvantageRow('Others Get Dividend', '₹${advantageData['first_month']['dividend_per_member'].toStringAsFixed(0)}', isHighlight: false), ], ), ), SizedBox(height: 12.h), // Last Month Winner Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: Colors.purple.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.purple.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.schedule, color: Colors.purple.shade600, size: 16.w), SizedBox(width: 8.w), Text( 'Last Month Winner (Late Advantage)', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.purple.shade700, ), ), ], ), SizedBox(height: 8.h), _buildAdvantageRow('Total Paid', '₹${advantageData['last_month']['payment'].toStringAsFixed(0)}'), _buildAdvantageRow('Total Received', '₹${advantageData['last_month']['receipt'].toStringAsFixed(0)}'), _buildAdvantageRow('Net Gain', '₹${advantageData['last_month']['net_gain'].toStringAsFixed(0)}', isHighlight: true), _buildAdvantageRow('Others Pay Extra', '₹${(advantageData['last_month']['dividend_per_member'] * -1).toStringAsFixed(0)}', isHighlight: false), ], ), ), SizedBox(height: 12.h), // Commission Info Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.orange.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.percent, color: Colors.orange.shade600, size: 16.w), SizedBox(width: 8.w), Text( 'Fixed Monthly Commission: ₹${advantageData['monthly_commission'].toStringAsFixed(0)}', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.orange.shade700, ), ), ], ), SizedBox(height: 8.h), _buildAdvantageRow('Subscription/Month', '₹${advantageData['subscription_per_month'].toStringAsFixed(0)}'), _buildAdvantageRow('Installment/Month', '₹${advantageData['installment_per_month'].toStringAsFixed(0)}'), _buildAdvantageRow('Winner Payout', '₹${advantageData['winner_payout'].toStringAsFixed(0)}'), _buildAdvantageRow('Early Month Dividend', '₹${advantageData['dividend_per_member_early'].toStringAsFixed(0)} per member'), ], ), ), ], ), ); } Widget _buildAdvantageRow(String label, String value, {bool isHighlight = false}) { return Padding( padding: EdgeInsets.symmetric(vertical: 2.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle( fontSize: 13.sp, color: Colors.grey.shade600, ), ), Text( value, style: TextStyle( fontSize: 13.sp, fontWeight: isHighlight ? FontWeight.w600 : FontWeight.w500, color: isHighlight ? Colors.green.shade700 : Colors.grey.shade800, ), ), ], ), ); } }