using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace ZB.MOM.WW.LocalDb.Registration;

/// <summary>
/// A table opted into replication: its primary-key columns (in PK ordinal order), all its
/// columns (in PRAGMA <c>cid</c> order), and a schema digest used to detect drift.
/// </summary>
public sealed record ReplicatedTable(
    string Name,
    IReadOnlyList<string> PkColumns,
    IReadOnlyList<(string Name, string Type)> Columns,
    string Digest)
{
    /// <summary>
    /// Lowercase-hex SHA-256 of <c>"{name}|pk:{p1,p2}|cols:{c1:TYPE,c2:TYPE,...}"</c> — PK columns
    /// in ordinal order, all columns in cid order. Every name/type component is length-prefixed
    /// (<c>{len}:{value}</c>) so no combination of names/types can collide with a different schema,
    /// and declared types have whitespace runs collapsed then uppercased so equivalent declarations
    /// digest identically.
    /// </summary>
    internal static string ComputeDigest(
        string name, IReadOnlyList<string> pkColumns, IReadOnlyList<(string Name, string Type)> columns)
    {
        var pk = string.Join(",", pkColumns.Select(LengthPrefixed));
        var cols = string.Join(",", columns.Select(c =>
            $"{LengthPrefixed(c.Name)}:{LengthPrefixed(NormalizeType(c.Type))}"));
        var canonical = $"{LengthPrefixed(name)}|pk:{pk}|cols:{cols}";
        var hash = SHA256.HashData(Encoding.UTF8.GetBytes(canonical));
        return Convert.ToHexStringLower(hash);
    }

    private static string LengthPrefixed(string value) => $"{value.Length}:{value}";

    private static string NormalizeType(string type) =>
        Regex.Replace(type.Trim(), @"\s+", " ").ToUpperInvariant();
}
