import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/attachments/blocs/attachments_bloc.dart'; import 'package:flux/features/operations/blocs/operations_cubit.dart'; import 'package:flux/features/operations/models/operation_model.dart'; import 'package:flux/core/widgets/shared_forms/shared_customer_section.dart'; import 'package:flux/features/operations/ui/widgets/details_section.dart'; import 'package:flux/core/widgets/shared_forms/shared_attachments_section.dart'; import 'package:flux/core/widgets/shared_forms/shared_staff_section.dart'; import 'package:get_it/get_it.dart'; class OperationFormScreen extends StatefulWidget { final String? operationId; final OperationModel? existingOperation; const OperationFormScreen({ super.key, this.operationId, this.existingOperation, }); @override State createState() => _OperationFormScreenState(); } class _OperationFormScreenState extends State { final _formKey = GlobalKey(); final _referenceController = TextEditingController(); final _noteController = TextEditingController(); final _freeTextSubtypeController = TextEditingController(); final _freeTextDescriptionController = TextEditingController(); final List _availableTypes = [ 'AL', 'MNP', 'NIP', 'UNICA', 'TELEPASS', 'Energy', 'Fin', 'Entertainment', 'Custom', ]; bool _isInitialized = false; @override void initState() { super.initState(); final cubit = context.read(); final currentLoggedStaff = GetIt.I .get() .state .currentStaffMember!; // 1. Diciamo al Cubit di prepararsi cubit.initOperationForm( existingOperation: widget.existingOperation, operationId: widget.operationId, staffId: currentLoggedStaff.id, staffDisplayName: currentLoggedStaff.name, ); // 2. IL TRUCCO MAGICO: // Se abbiamo passato existingOperation, il Cubit si è appena aggiornato. // Lo stato è già pronto, quindi sincronizziamo i controller SUBITO! if (cubit.state.currentOperation != null) { _syncTextControllers(cubit.state.currentOperation!); } } @override void dispose() { _referenceController.dispose(); _noteController.dispose(); _freeTextSubtypeController.dispose(); super.dispose(); } void _syncTextControllers(OperationModel model) { if (_referenceController.text.isEmpty && model.reference.isNotEmpty) { _referenceController.text = model.reference; } if (_noteController.text.isEmpty && model.note.isNotEmpty) { _noteController.text = model.note; } if (_freeTextSubtypeController.text.isEmpty && model.subtype != null && model.subtype!.isNotEmpty) { _freeTextSubtypeController.text = model.subtype!; } if (_freeTextDescriptionController.text.isEmpty && model.description != null && model.description!.isNotEmpty) { _freeTextDescriptionController.text = model.description!; } _isInitialized = true; } void _saveOperation({required bool keepAdding}) { if (_formKey.currentState!.validate()) { final cubit = context.read(); final currentOperation = cubit.state.currentOperation!; final operationToSave = currentOperation.copyWith( reference: _referenceController.text, note: _noteController.text, subtype: ['Entertainment', 'Custom'].contains(currentOperation.type) ? _freeTextSubtypeController.text : currentOperation.subtype, description: ['Energy', 'Custom'].contains(currentOperation.type) ? _freeTextDescriptionController.text : currentOperation.description, ); cubit.initOperationForm(existingOperation: operationToSave); cubit.saveCurrentOperation( targetStatus: OperationStatus.ok, shouldPop: !keepAdding, ); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); return BlocConsumer( listenWhen: (previous, current) => previous.status != current.status || previous.currentOperation?.id != current.currentOperation?.id, listener: (context, state) { if (state.status == OperationsStatus.ready && state.currentOperation != null && !_isInitialized) { _syncTextControllers(state.currentOperation!); } if (state.status == OperationsStatus.saved) { Navigator.of(context).pop(); } else if (state.status == OperationsStatus.savedNoPop) { context.read().prepareNextOperationInBatch(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Servizio aggiunto! Inserisci il prossimo.'), ), ); _freeTextSubtypeController.clear(); _freeTextDescriptionController.clear(); } else if (state.status == OperationsStatus.failure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.errorMessage ?? 'Errore'), backgroundColor: theme.colorScheme.error, ), ); } }, builder: (context, state) { if (!_isInitialized && (widget.operationId != null || widget.existingOperation != null) && state.status == OperationsStatus.loading) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } return Scaffold( appBar: AppBar( title: Text( state.currentOperation?.id == null ? 'Nuova Pratica' : 'Modifica Pratica', ), ), body: Form( key: _formKey, child: LayoutBuilder( builder: (context, constraints) { final isUltraWide = constraints.maxWidth > 1400; final isDesktop = constraints.maxWidth > 900; if (isUltraWide) { // --- LAYOUT 3 COLONNE (Schermi giganti) --- return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 1. FORM PRINCIPALE (40%) Expanded( flex: 4, child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), // Attenzione: devi togliere la sezione file dal _buildMainFormContent! child: _buildMainFormContent( theme, state, showFiles: false, ), ), ), VerticalDivider(width: 1, color: theme.dividerColor), // 2. NOTE (30%) Expanded( flex: 3, child: Padding( padding: const EdgeInsets.all(16.0), child: _buildNotesSection(isDesktop: true), ), ), VerticalDivider(width: 1, color: theme.dividerColor), // 3. FILE (30%) Expanded( flex: 3, child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: SharedAttachmentsSection( parentType: AttachmentParentType.operation, parentId: state.currentOperation?.id, ), ), ), ], ); } else if (isDesktop) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 7, child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: _buildMainFormContent(theme, state), ), ), VerticalDivider(width: 1, color: theme.dividerColor), Expanded( flex: 3, child: Padding( padding: const EdgeInsets.all(16.0), child: _buildNotesSection(isDesktop: true), ), ), ], ); } else { return SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildMainFormContent(theme, state), const Divider(height: 32), _buildNotesSection(isDesktop: false), const SizedBox(height: 80), ], ), ); } }, ), ), bottomNavigationBar: SafeArea( child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ Expanded( flex: 1, child: OutlinedButton( onPressed: state.status == OperationsStatus.saving ? null : () => _saveOperation(keepAdding: true), child: const Text( 'Salva e Aggiungi Altro', textAlign: TextAlign.center, ), ), ), const SizedBox(width: 12), Expanded( flex: 1, child: ElevatedButton( onPressed: state.status == OperationsStatus.saving ? null : () => _saveOperation(keepAdding: false), child: state.status == OperationsStatus.saving ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Text('Salva ed Esci'), ), ), ], ), ), ), ); }, ); } Widget _buildMainFormContent( ThemeData theme, OperationsState state, { bool showFiles = true, }) { final currentOp = state.currentOperation; final currentType = currentOp?.type ?? 'AL'; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ StaffSection( staffId: currentOp?.staffId, staffName: currentOp?.staffDisplayName, onStaffSelected: (staff) => { context.read().updateOperationFields( staffId: staff.id, staffDisplayName: staff.name, ), }, ), const Divider(height: 50), _buildSectionTitle('Cliente & Riferimento'), SharedCustomerSection( customerId: currentOp?.customerId, customerName: currentOp?.customerDisplayName, onCustomerSelected: (customer) { context.read().updateOperationFields( customerId: customer.id, customerDisplayName: customer.name, ); }, ), const SizedBox(height: 16), TextFormField( controller: _referenceController, decoration: const InputDecoration( labelText: 'Riferimento (es. numero di telefono, targa...)', prefixIcon: Icon(Icons.tag), ), ), const Divider(height: 32), _buildSectionTitle('Cosa stiamo facendo?'), Wrap( spacing: 8.0, runSpacing: 8.0, children: _availableTypes.map((type) { return ChoiceChip( label: Text(type), selected: currentType == type, onSelected: (selected) { if (selected) { context.read().setTypeWithSmartDefault(type); } }, ); }).toList(), ), const Divider(height: 32), _buildSectionTitle('Dettagli Servizio'), DetailsSection( currentOp: currentOp, currentType: currentType, freeTextSubtypeController: _freeTextSubtypeController, freeTextDescriptionController: _freeTextDescriptionController, durationQuickPicks: _buildDurationQuickPicks(currentOp), ), // QUANTITÀ Row( children: [ const Text('Quantità: '), IconButton( icon: const Icon(Icons.remove), onPressed: () { final q = currentOp?.quantity ?? 1; if (q > 1) { context.read().updateOperationFields( quantity: q - 1, ); } }, ), Text( '${currentOp?.quantity ?? 1}', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.add), onPressed: () { final q = currentOp?.quantity ?? 1; context.read().updateOperationFields( quantity: q + 1, ); }, ), ], ), const Divider(height: 32), if (showFiles) ...[ SharedAttachmentsSection( parentType: AttachmentParentType.operation, parentId: currentOp?.id, ), ], ], ); } Widget _buildDurationQuickPicks(OperationModel? currentOp) { final durations = [3, 6, 12, 24, 30, 36, 48]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Imposta durata rapida (mesi):", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.grey, ), ), const SizedBox(height: 8), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: durations.map((months) { return Padding( padding: const EdgeInsets.only(right: 8.0), child: ActionChip( label: Text("$months m"), backgroundColor: Colors.blue.withValues(alpha: 0.05), onPressed: () { final now = DateTime.now(); context.read().updateOperationFields( expirationDate: DateTime( now.year, now.month + months, now.day, ), ); }, ), ); }).toList(), ), ), ], ); } Widget _buildNotesSection({required bool isDesktop}) { final title = _buildSectionTitle('Note Interne'); final noteField = TextFormField( controller: _noteController, keyboardType: TextInputType.multiline, minLines: isDesktop ? null : 5, maxLines: null, expands: isDesktop, textAlignVertical: TextAlignVertical.top, decoration: const InputDecoration( hintText: 'Incolla qui seriali, ICCID, IBAN, indirizzi...', alignLabelWithHint: true, border: OutlineInputBorder(), ), ); return isDesktop ? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ title, const SizedBox(height: 8), Expanded(child: noteField), ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [title, const SizedBox(height: 8), noteField], ); } Widget _buildSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(bottom: 12.0), child: Text( title, style: Theme.of( context, ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), ), ); } }