uto_manager/lib/domain/entities/personnel_record.dart

141 lines
4.3 KiB
Dart

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<String> 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<String>? 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<Object?> 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})';
}