import 'package:flutter/material.dart'; import 'package:uto_manager/domain/entities/authorized_rank.dart'; import 'package:uto_manager/domain/entities/position_slot.dart'; import 'package:uto_manager/domain/value_objects/duty_mos.dart'; import 'package:uuid/uuid.dart'; /// Dialog for creating or editing a [PositionSlot] within a unit. /// /// Pass [existing] to edit; leave null to create a new slot. /// [unitId] is required and identifies which unit owns this slot. class AddEditSlotDialog extends StatefulWidget { const AddEditSlotDialog({ required this.unitId, super.key, this.existing, }); final String unitId; final PositionSlot? existing; @override State createState() => _AddEditSlotDialogState(); } class _AddEditSlotDialogState extends State { final _formKey = GlobalKey(); late final TextEditingController _titleCtrl; late final TextEditingController _mosCtrl; late AuthorizedRank _rank; late bool _isKeyLeader; List _mosSuggestions = []; bool get _isEditing => widget.existing != null; @override void initState() { super.initState(); final e = widget.existing; _titleCtrl = TextEditingController(text: e?.positionTitle ?? ''); _mosCtrl = TextEditingController(text: e?.dutyMos.code ?? ''); _rank = e?.authorizedRank ?? AuthorizedRank.e4; _isKeyLeader = e?.isKeyLeader ?? false; } @override void dispose() { _titleCtrl.dispose(); _mosCtrl.dispose(); super.dispose(); } void _updateMosSuggestions(String query) { if (query.isEmpty) { setState(() => _mosSuggestions = []); return; } final q = query.toUpperCase(); final matches = DutyMos.allCodes.where((c) => c.startsWith(q) || c.contains(q)).take(12).toList()..sort(); setState(() => _mosSuggestions = matches); } void _submit() { if (!_formKey.currentState!.validate()) return; final mosCode = _mosCtrl.text.trim().toUpperCase(); DutyMos mos; try { mos = DutyMos(mosCode); } catch (_) { mos = DutyMos.unvalidated(mosCode); } final slot = PositionSlot( slotId: widget.existing?.slotId ?? const Uuid().v4(), unitId: widget.unitId, positionTitle: _titleCtrl.text.trim(), dutyMos: mos, authorizedRank: _rank, isKeyLeader: _isKeyLeader, assignedPersonnelId: widget.existing?.assignedPersonnelId, ); Navigator.of(context).pop(slot); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return AlertDialog( title: Row( children: [ Icon(_isEditing ? Icons.edit : Icons.add_circle_outline, size: 20), const SizedBox(width: 8), Text(_isEditing ? 'Edit Position Slot' : 'Add Position Slot'), ], ), content: SizedBox( width: 400, child: Form( key: _formKey, child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Position Title TextFormField( controller: _titleCtrl, decoration: const InputDecoration( labelText: 'Position Title', hintText: 'e.g. Platoon Leader, Squad Leader, Medic', prefixIcon: Icon(Icons.work_history_outlined), ), textCapitalization: TextCapitalization.words, validator: (v) { if (v == null || v.trim().isEmpty) return 'Position title is required'; return null; }, ), const SizedBox(height: 12), // Authorized Rank DropdownButtonFormField( initialValue: _rank, decoration: const InputDecoration( labelText: 'Authorized Rank', prefixIcon: Icon(Icons.military_tech_outlined), ), items: AuthorizedRank.values.map((r) { return DropdownMenuItem( value: r, child: Text('${r.payGrade} — ${r.rankTitle}'), ); }).toList(), onChanged: (v) => setState(() => _rank = v!), ), const SizedBox(height: 12), // Duty MOS with autocomplete TextFormField( controller: _mosCtrl, decoration: const InputDecoration( labelText: 'Duty MOS', hintText: 'e.g. 11B, 68W, 25U', prefixIcon: Icon(Icons.badge_outlined), ), textCapitalization: TextCapitalization.characters, onChanged: _updateMosSuggestions, validator: (v) { if (v == null || v.trim().isEmpty) return 'Duty MOS is required'; final code = v.trim().toUpperCase(); if (!DutyMos.isKnown(code)) { return 'Unknown MOS code (e.g. 11B, 68W, 25U)'; } return null; }, ), if (_mosSuggestions.isNotEmpty) ...[ const SizedBox(height: 4), Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerHigh, borderRadius: BorderRadius.circular(6), border: Border.all(color: theme.colorScheme.outlineVariant), ), child: Wrap( spacing: 4, runSpacing: 4, children: _mosSuggestions.map((code) { return ActionChip( label: Text( code, style: theme.textTheme.labelSmall?.copyWith( fontWeight: FontWeight.bold, ), ), onPressed: () { _mosCtrl.text = code; setState(() => _mosSuggestions = []); }, padding: const EdgeInsets.symmetric(horizontal: 4), visualDensity: VisualDensity.compact, ); }).toList(), ), ), ], const SizedBox(height: 8), // Key Leader toggle SwitchListTile( title: const Text('Key Leader Position'), subtitle: const Text('e.g. Commander, XO, Platoon Leader, PSG'), value: _isKeyLeader, onChanged: (v) => setState(() => _isKeyLeader = v), contentPadding: EdgeInsets.zero, dense: true, ), ], ), ), ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), FilledButton.icon( icon: Icon(_isEditing ? Icons.save : Icons.add, size: 16), label: Text(_isEditing ? 'Save Changes' : 'Add Slot'), onPressed: _submit, ), ], ); } }