using System.Text.Json;
using System.Text.Json.Serialization;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers;

/// <summary>
///     Mutable, all-nullable form model for the driver resilience override. Binds the typed
///     fields in DriverResilienceSection; null/blank = "use the driver's tier default", so a
///     blank form serializes back to null (preserving DriverInstance.ResilienceConfig = null).
///     Emits / reads the exact override JSON shape DriverResilienceOptionsParser consumes.
/// </summary>
public sealed class ResilienceFormModel
{
    public static readonly string[] Capabilities =
        ["Read", "Write", "Discover", "Subscribe", "Probe", "AlarmSubscribe", "AlarmAcknowledge", "HistoryRead"];

    public int? BulkheadMaxConcurrent { get; set; }
    public int? BulkheadMaxQueue { get; set; }
    public int? RecycleIntervalSeconds { get; set; }

    // capability name -> (timeout, retry, breaker), each nullable.
    public Dictionary<string, CapabilityRow> Policies { get; set; } =
        Capabilities.ToDictionary(c => c, _ => new CapabilityRow(), StringComparer.OrdinalIgnoreCase);

    public sealed class CapabilityRow
    {
        public int? TimeoutSeconds { get; set; }
        public int? RetryCount { get; set; }
        public int? BreakerFailureThreshold { get; set; }
        public bool IsEmpty => TimeoutSeconds is null && RetryCount is null && BreakerFailureThreshold is null;
    }

    private static readonly JsonSerializerOptions ReadOpts = new() { PropertyNameCaseInsensitive = true };
    private static readonly JsonSerializerOptions WriteOpts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    };

    public static ResilienceFormModel FromJson(string? json)
    {
        var model = new ResilienceFormModel();
        if (string.IsNullOrWhiteSpace(json)) return model;

        Shape? shape;
        try { shape = JsonSerializer.Deserialize<Shape>(json, ReadOpts); }
        catch (JsonException) { return model; }   // malformed -> empty form; raw view (next task) shows the text
        if (shape is null) return model;

        model.BulkheadMaxConcurrent = shape.BulkheadMaxConcurrent;
        model.BulkheadMaxQueue = shape.BulkheadMaxQueue;
        model.RecycleIntervalSeconds = shape.RecycleIntervalSeconds;
        if (shape.CapabilityPolicies is not null)
            foreach (var (cap, p) in shape.CapabilityPolicies)
                if (model.Policies.TryGetValue(cap, out var row))
                {
                    row.TimeoutSeconds = p.TimeoutSeconds;
                    row.RetryCount = p.RetryCount;
                    row.BreakerFailureThreshold = p.BreakerFailureThreshold;
                }
        return model;
    }

    /// <summary>Emit only the non-null overrides; returns null when nothing is overridden.</summary>
    public string? ToJson()
    {
        var caps = Policies
            .Where(kv => !kv.Value.IsEmpty)
            .ToDictionary(kv => kv.Key, kv => new PolicyShape
            {
                TimeoutSeconds = kv.Value.TimeoutSeconds,
                RetryCount = kv.Value.RetryCount,
                BreakerFailureThreshold = kv.Value.BreakerFailureThreshold,
            });

        var hasAny = BulkheadMaxConcurrent is not null || BulkheadMaxQueue is not null
                     || RecycleIntervalSeconds is not null || caps.Count > 0;
        if (!hasAny) return null;

        var shape = new Shape
        {
            BulkheadMaxConcurrent = BulkheadMaxConcurrent,
            BulkheadMaxQueue = BulkheadMaxQueue,
            RecycleIntervalSeconds = RecycleIntervalSeconds,
            CapabilityPolicies = caps.Count > 0 ? caps : null,
        };
        return JsonSerializer.Serialize(shape, WriteOpts);
    }

    private sealed class Shape
    {
        public int? BulkheadMaxConcurrent { get; set; }
        public int? BulkheadMaxQueue { get; set; }
        public int? RecycleIntervalSeconds { get; set; }
        public Dictionary<string, PolicyShape>? CapabilityPolicies { get; set; }
    }

    private sealed class PolicyShape
    {
        public int? TimeoutSeconds { get; set; }
        public int? RetryCount { get; set; }
        public int? BreakerFailureThreshold { get; set; }
    }
}
