using ColaFlow.Shared.Kernel.Common;
namespace ColaFlow.Modules.Mcp.Domain.ValueObjects;
///
/// Value object representing a preview of changes proposed by an AI agent
/// Immutable - once created, cannot be modified
///
public sealed class DiffPreview : ValueObject
{
///
/// The type of operation: CREATE, UPDATE, DELETE
///
public string Operation { get; private set; }
///
/// The type of entity being changed (e.g., "Epic", "Story", "Task")
///
public string EntityType { get; private set; }
///
/// The ID of the entity being changed (null for CREATE operations)
///
public Guid? EntityId { get; private set; }
///
/// Human-readable key for the entity (e.g., "COLA-146")
///
public string? EntityKey { get; private set; }
///
/// Snapshot of the entity state before the change (null for CREATE)
/// Stored as JSON for flexibility
///
public string? BeforeData { get; private set; }
///
/// Snapshot of the entity state after the change (null for DELETE)
/// Stored as JSON for flexibility
///
public string? AfterData { get; private set; }
///
/// List of individual field changes (for UPDATE operations)
///
public IReadOnlyList ChangedFields { get; private set; }
///
/// Private constructor for EF Core
///
private DiffPreview()
{
Operation = string.Empty;
EntityType = string.Empty;
ChangedFields = new List().AsReadOnly();
}
///
/// Create a new DiffPreview
///
public DiffPreview(
string operation,
string entityType,
Guid? entityId,
string? entityKey,
string? beforeData,
string? afterData,
IReadOnlyList? changedFields = null)
{
// Validation
if (string.IsNullOrWhiteSpace(operation))
throw new ArgumentException("Operation cannot be empty", nameof(operation));
if (string.IsNullOrWhiteSpace(entityType))
throw new ArgumentException("EntityType cannot be empty", nameof(entityType));
// Normalize operation to uppercase
operation = operation.ToUpperInvariant();
// Validate operation type
if (operation != "CREATE" && operation != "UPDATE" && operation != "DELETE")
throw new ArgumentException(
"Operation must be CREATE, UPDATE, or DELETE",
nameof(operation));
// Validate operation-specific requirements
if (operation == "UPDATE" && entityId == null)
throw new ArgumentException(
"UPDATE operation requires EntityId",
nameof(entityId));
if (operation == "UPDATE" && (changedFields == null || changedFields.Count == 0))
throw new ArgumentException(
"UPDATE operation must have at least one changed field",
nameof(changedFields));
if (operation == "DELETE" && entityId == null)
throw new ArgumentException(
"DELETE operation requires EntityId",
nameof(entityId));
if (operation == "CREATE" && string.IsNullOrWhiteSpace(afterData))
throw new ArgumentException(
"CREATE operation requires AfterData",
nameof(afterData));
Operation = operation;
EntityType = entityType;
EntityId = entityId;
EntityKey = entityKey;
BeforeData = beforeData;
AfterData = afterData;
ChangedFields = changedFields ?? new List().AsReadOnly();
}
///
/// Factory method to create a CREATE operation diff
///
public static DiffPreview ForCreate(
string entityType,
string afterData,
string? entityKey = null)
{
return new DiffPreview(
operation: "CREATE",
entityType: entityType,
entityId: null,
entityKey: entityKey,
beforeData: null,
afterData: afterData,
changedFields: null);
}
///
/// Factory method to create an UPDATE operation diff
///
public static DiffPreview ForUpdate(
string entityType,
Guid entityId,
string beforeData,
string afterData,
IReadOnlyList changedFields,
string? entityKey = null)
{
return new DiffPreview(
operation: "UPDATE",
entityType: entityType,
entityId: entityId,
entityKey: entityKey,
beforeData: beforeData,
afterData: afterData,
changedFields: changedFields);
}
///
/// Factory method to create a DELETE operation diff
///
public static DiffPreview ForDelete(
string entityType,
Guid entityId,
string beforeData,
string? entityKey = null)
{
return new DiffPreview(
operation: "DELETE",
entityType: entityType,
entityId: entityId,
entityKey: entityKey,
beforeData: beforeData,
afterData: null,
changedFields: null);
}
///
/// Value object equality - compare all atomic values
///
protected override IEnumerable