using System.Globalization;
using System.Text.Json;
using ZB.MOM.WW.ScadaBridge.Commons.Types.DataConnections;

namespace ZB.MOM.WW.ScadaBridge.Commons.Serialization;

/// <summary>
/// Serializes <see cref="MxGatewayEndpointConfig"/> to/from the typed JSON stored in
/// <c>DataConnection.PrimaryConfiguration</c> / <c>BackupConfiguration</c>, and flattens
/// it to the <c>IDictionary&lt;string,string&gt;</c> shape <c>IDataConnection.ConnectAsync</c>
/// expects. MxGateway is net-new, so there is no legacy shape to recover — a row that
/// fails to parse yields a default config.
/// </summary>
public static class MxGatewayEndpointConfigSerializer
{
    private static readonly JsonSerializerOptions JsonOpts = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false,
    };

    /// <summary>Serializes a config to the typed JSON shape.</summary>
    /// <param name="config">The endpoint configuration to serialize.</param>
    /// <returns>A camelCase JSON string representing the endpoint configuration.</returns>
    public static string Serialize(MxGatewayEndpointConfig config)
        => JsonSerializer.Serialize(config, JsonOpts);

    /// <summary>Parses stored config JSON; null/blank/malformed yields a default config.</summary>
    /// <param name="json">The stored JSON string.</param>
    /// <returns>The deserialized <see cref="MxGatewayEndpointConfig"/>, or a default instance if the input is null, blank, or malformed.</returns>
    public static MxGatewayEndpointConfig Deserialize(string? json)
    {
        if (string.IsNullOrWhiteSpace(json)) return new MxGatewayEndpointConfig();
        try { return JsonSerializer.Deserialize<MxGatewayEndpointConfig>(json, JsonOpts) ?? new MxGatewayEndpointConfig(); }
        catch (JsonException) { return new MxGatewayEndpointConfig(); }
    }

    /// <summary>Flattens the typed config to the key-value shape the adapter consumes.</summary>
    /// <param name="c">The endpoint configuration to flatten.</param>
    /// <returns>A string-keyed dictionary containing all endpoint configuration properties.</returns>
    public static IDictionary<string, string> ToFlatDict(MxGatewayEndpointConfig c) => new Dictionary<string, string>
    {
        ["Endpoint"] = c.Endpoint,
        ["ApiKey"] = c.ApiKey,
        ["ClientName"] = c.ClientName,
        ["WriteUserId"] = c.WriteUserId.ToString(CultureInfo.InvariantCulture),
        ["UseTls"] = c.UseTls.ToString(),
        ["CaFile"] = c.CaFile,
        ["ServerName"] = c.ServerName,
        ["ReadTimeoutMs"] = c.ReadTimeoutMs.ToString(CultureInfo.InvariantCulture),
    };

    /// <summary>Reconstructs a config from the flat key-value shape; invalid numerics fall back to defaults.</summary>
    /// <param name="d">The flat dictionary.</param>
    /// <returns>A <see cref="MxGatewayEndpointConfig"/> populated from the dictionary; missing or invalid entries use default values.</returns>
    public static MxGatewayEndpointConfig FromFlatDict(IDictionary<string, string> d)
    {
        var c = new MxGatewayEndpointConfig();
        if (d.TryGetValue("Endpoint", out var ep) && !string.IsNullOrWhiteSpace(ep)) c.Endpoint = ep;
        if (d.TryGetValue("ApiKey", out var ak)) c.ApiKey = ak;
        if (d.TryGetValue("ClientName", out var cn)) c.ClientName = cn;
        if (d.TryGetValue("WriteUserId", out var wu) && int.TryParse(wu, out var wuv)) c.WriteUserId = wuv;
        if (d.TryGetValue("UseTls", out var tls) && bool.TryParse(tls, out var tlsv)) c.UseTls = tlsv;
        if (d.TryGetValue("CaFile", out var ca)) c.CaFile = ca;
        if (d.TryGetValue("ServerName", out var sn)) c.ServerName = sn;
        if (d.TryGetValue("ReadTimeoutMs", out var rt) && int.TryParse(rt, out var rtv)) c.ReadTimeoutMs = rtv;
        return c;
    }
}
