namespace KArtSell.Modules.IdentityAccess.ManageIdentityAndRoles.Domain;
///
/// Role Assignment workflow state (Maker-Checker pattern)
/// AEG-VS-01-03: Immutable value object for approval workflow
///
public sealed record RoleAssignmentState
{
public const string PendingApproval = "PENDING_APPROVAL";
public const string ApprovedBy1 = "APPROVED_BY_1";
public const string ApprovedBy2 = "APPROVED_BY_2";
public const string Active = "ACTIVE";
public const string Expired = "EXPIRED";
public const string Revoked = "REVOKED";
public const string Rejected = "REJECTED";
private static readonly HashSet ValidStates =
[
PendingApproval, ApprovedBy1, ApprovedBy2, Active, Expired, Revoked, Rejected
];
public string Value { get; }
private RoleAssignmentState(string value)
{
if (!ValidStates.Contains(value))
throw new ArgumentException($"Invalid role assignment state: {value}", nameof(value));
Value = value;
}
// Factory methods
public static RoleAssignmentState CreatePending() => new(PendingApproval);
public static RoleAssignmentState Activate() => new(Active);
public static RoleAssignmentState Expire() => new(Expired);
public static RoleAssignmentState Revoke() => new(Revoked);
public static RoleAssignmentState Reject() => new(Rejected);
public static RoleAssignmentState Parse(string value) => new(value);
// State transitions
public RoleAssignmentState ApproveByFirst()
{
return Value switch
{
PendingApproval => new(ApprovedBy1),
_ => throw new InvalidOperationException($"Cannot approve from {Value}")
};
}
public RoleAssignmentState ApproveBySecond()
{
return Value switch
{
ApprovedBy1 => new(ApprovedBy2),
_ => throw new InvalidOperationException($"Cannot approve second from {Value}")
};
}
public RoleAssignmentState ActivateAfterApproval()
{
return Value switch
{
ApprovedBy2 => new(Active),
_ => throw new InvalidOperationException($"Cannot activate from {Value}")
};
}
public RoleAssignmentState ExpireTimebound()
{
return Value switch
{
Active => new(Expired),
_ => throw new InvalidOperationException($"Cannot expire from {Value}")
};
}
public RoleAssignmentState RevokeActive()
{
return Value switch
{
Active or Expired => new(Revoked),
_ => throw new InvalidOperationException($"Cannot revoke from {Value}")
};
}
public RoleAssignmentState RejectRequest()
{
return Value switch
{
PendingApproval or ApprovedBy1 => new(Rejected),
_ => throw new InvalidOperationException($"Cannot reject from {Value}")
};
}
// State queries
public bool IsPending() => Value == PendingApproval;
public bool IsAwaitingSecondApproval() => Value == ApprovedBy1;
public bool IsApproved() => Value == ApprovedBy2;
public bool IsActive() => Value == Active;
public bool IsExpired() => Value == Expired;
public bool IsRevoked() => Value == Revoked;
public bool IsRejected() => Value == Rejected;
public bool CanApprove() => Value is PendingApproval or ApprovedBy1;
public bool RequiresSecondApproval() => Value == ApprovedBy1;
public override string ToString() => Value;
}