using ColaFlow.Shared.Kernel.Common;

namespace ColaFlow.Modules.Mcp.Domain.ValueObjects;

/// <summary>
/// Value object representing a single field difference in a change preview
/// </summary>
public sealed class DiffField : ValueObject
{
    /// <summary>
    /// The name of the field that changed (e.g., "Title", "Status")
    /// </summary>
    public string FieldName { get; private set; }

    /// <summary>
    /// Human-readable display name for the field
    /// </summary>
    public string DisplayName { get; private set; }

    /// <summary>
    /// The old value before the change
    /// </summary>
    public object? OldValue { get; private set; }

    /// <summary>
    /// The new value after the change
    /// </summary>
    public object? NewValue { get; private set; }

    /// <summary>
    /// Optional HTML diff markup for rich text fields
    /// </summary>
    public string? DiffHtml { get; private set; }

    /// <summary>
    /// Private constructor for EF Core
    /// </summary>
    private DiffField()
    {
        FieldName = string.Empty;
        DisplayName = string.Empty;
    }

    /// <summary>
    /// Create a new DiffField
    /// </summary>
    public DiffField(
        string fieldName,
        string displayName,
        object? oldValue,
        object? newValue,
        string? diffHtml = null)
    {
        if (string.IsNullOrWhiteSpace(fieldName))
            throw new ArgumentException("Field name cannot be empty", nameof(fieldName));

        if (string.IsNullOrWhiteSpace(displayName))
            throw new ArgumentException("Display name cannot be empty", nameof(displayName));

        FieldName = fieldName;
        DisplayName = displayName;
        OldValue = oldValue;
        NewValue = newValue;
        DiffHtml = diffHtml;
    }

    /// <summary>
    /// Value object equality - compare all atomic values
    /// </summary>
    protected override IEnumerable<object> GetAtomicValues()
    {
        yield return FieldName;
        yield return DisplayName;
        yield return OldValue ?? string.Empty;
        yield return NewValue ?? string.Empty;
        yield return DiffHtml ?? string.Empty;
    }

    /// <summary>
    /// Check if the field value actually changed
    /// </summary>
    public bool HasChanged()
    {
        if (OldValue == null && NewValue == null)
            return false;

        if (OldValue == null || NewValue == null)
            return true;

        return !OldValue.Equals(NewValue);
    }

    /// <summary>
    /// Get a formatted string representation of the change
    /// </summary>
    public string GetChangeDescription()
    {
        if (OldValue == null && NewValue == null)
            return $"{DisplayName}: (no change)";

        if (OldValue == null)
            return $"{DisplayName}: → {NewValue}";

        if (NewValue == null)
            return $"{DisplayName}: {OldValue} → (removed)";

        return $"{DisplayName}: {OldValue} → {NewValue}";
    }
}
