using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;

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

/// <summary>
///     Typed working model for an AB Legacy <c>Device</c>'s connection endpoint (the v3 endpoint→DeviceConfig
///     split). Authors the <b>PascalCase</b> <c>HostAddress</c>/<c>PlcFamily</c> keys that
///     <c>AbLegacyDeviceOptions</c> binds — the exact casing the seed and runtime probe
///     (<c>PropertyNameCaseInsensitive</c>) expect. Preserves unrecognised keys across a load→save.
/// </summary>
public sealed class AbLegacyDeviceModel
{
    /// <summary>PLC host / IP address.</summary>
    public string HostAddress { get; set; } = "";

    /// <summary>Allen-Bradley legacy PLC family (SLC500 / MicroLogix / PLC-5).</summary>
    public AbLegacyPlcFamily PlcFamily { get; set; } = AbLegacyPlcFamily.Slc500;

    private System.Text.Json.Nodes.JsonObject _bag = new();

    /// <summary>Loads a model from a DeviceConfig JSON string, defaulting absent keys and retaining
    /// every original key so fields this editor doesn't expose survive a load→save.</summary>
    /// <param name="json">The raw DeviceConfig JSON string, or null for a new/empty device.</param>
    /// <returns>The populated <see cref="AbLegacyDeviceModel"/>.</returns>
    public static AbLegacyDeviceModel FromJson(string? json)
    {
        var o = TagConfigJson.ParseOrNew(json);
        return new AbLegacyDeviceModel
        {
            HostAddress = TagConfigJson.GetString(o, "HostAddress") ?? "",
            PlcFamily = TagConfigJson.GetEnum(o, "PlcFamily", AbLegacyPlcFamily.Slc500),
            _bag = o,
        };
    }

    /// <summary>Serializes this model back to a DeviceConfig JSON string, writing the PascalCase endpoint
    /// keys over the preserved key bag.</summary>
    /// <returns>The serialised DeviceConfig JSON string.</returns>
    public string ToJson()
    {
        TagConfigJson.Set(_bag, "HostAddress", HostAddress);
        TagConfigJson.Set(_bag, "PlcFamily", PlcFamily);
        return TagConfigJson.Serialize(_bag);
    }

    /// <summary>Validation hook; returns an error message or null when the model is valid.</summary>
    /// <returns>An error message describing the validation failure, or <c>null</c> when the model is valid.</returns>
    public string? Validate()
        => string.IsNullOrWhiteSpace(HostAddress) ? "Host address is required." : null;
}
