import 'package:equatable/equatable.dart'; import 'package:uto_manager/domain/entities/authorized_rank.dart'; import 'package:uto_manager/domain/value_objects/duty_mos.dart'; /// Represents the readiness state of a soldier. enum ReadinessState { /// Fully mission-capable; no limiting factors. fullyMissionCapable, /// Partially mission-capable; some limiting factors present. partiallyMissionCapable, /// Not mission-capable; significant limiting factors. notMissionCapable, /// Status unknown or not yet assessed. unknown; /// Returns a human-readable display name. String get displayName { switch (this) { case ReadinessState.fullyMissionCapable: return 'FMC'; case ReadinessState.partiallyMissionCapable: return 'PMC'; case ReadinessState.notMissionCapable: return 'NMC'; case ReadinessState.unknown: return 'Unknown'; } } } /// Represents a soldier's personnel record in the UTO system. /// /// Contains identifying information, MOS qualifications, pay grade, /// and current readiness state. /// /// [name] is optional. When omitted the soldier is identified by /// [positionTitle] (e.g. "Team Leader", "Rifleman"). class PersonnelRecord extends Equatable { const PersonnelRecord({ required this.soldierId, required this.primaryMos, required this.payGrade, required this.readinessState, this.name, this.positionTitle, this.qualifications = const [], this.assignedSlotId, }); /// Unique identifier for this soldier (UUID v4). final String soldierId; /// The soldier's full name (Last, First MI format), or null if unnamed. final String? name; /// The soldier's duty position title (e.g. "Team Leader", "Rifleman"). /// /// Used as the display label when [name] is null. final String? positionTitle; /// The soldier's primary Military Occupational Specialty. final DutyMos primaryMos; /// The soldier's current pay grade. final AuthorizedRank payGrade; /// Additional MOS qualifications and special skills. final List qualifications; /// The current readiness state of this soldier. final ReadinessState readinessState; /// The ID of the position slot this soldier is assigned to, or null. final String? assignedSlotId; /// Returns the best available display label for this soldier. /// /// Prefers [name]; falls back to [positionTitle]; then a generic label. String get displayLabel { if (name != null && name!.isNotEmpty) return name!; if (positionTitle != null && positionTitle!.isNotEmpty) return positionTitle!; return '(Unnamed Soldier)'; } /// Returns true if this soldier is currently assigned to a position. bool get isAssigned => assignedSlotId != null; /// Returns true if this soldier is available for assignment. bool get isUnassigned => assignedSlotId == null; /// Returns true if this soldier is fully mission capable. bool get isFmc => readinessState == ReadinessState.fullyMissionCapable; /// Returns a copy of this [PersonnelRecord] with the given fields replaced. PersonnelRecord copyWith({ String? soldierId, String? name, bool clearName = false, String? positionTitle, bool clearPositionTitle = false, DutyMos? primaryMos, AuthorizedRank? payGrade, List? qualifications, ReadinessState? readinessState, String? assignedSlotId, bool clearAssignment = false, }) { return PersonnelRecord( soldierId: soldierId ?? this.soldierId, name: clearName ? null : (name ?? this.name), positionTitle: clearPositionTitle ? null : (positionTitle ?? this.positionTitle), primaryMos: primaryMos ?? this.primaryMos, payGrade: payGrade ?? this.payGrade, qualifications: qualifications ?? this.qualifications, readinessState: readinessState ?? this.readinessState, assignedSlotId: clearAssignment ? null : (assignedSlotId ?? this.assignedSlotId), ); } @override List get props => [ soldierId, name, positionTitle, primaryMos, payGrade, qualifications, readinessState, assignedSlotId, ]; @override String toString() => 'PersonnelRecord(id: $soldierId, label: $displayLabel, ' 'mos: ${primaryMos.code}, grade: ${payGrade.payGrade}, ' 'readiness: ${readinessState.displayName})'; }