using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using StellaOps.Scanner.WebService.Domain;

namespace StellaOps.Scanner.WebService.Utilities;

internal static class ScanIdGenerator
{
    public static ScanId Create(
        ScanTarget target,
        bool force,
        string? clientRequestId,
        IReadOnlyDictionary<string, string>? metadata)
    {
        ArgumentNullException.ThrowIfNull(target);

        var builder = new StringBuilder();
        builder.Append('|');
        builder.Append(target.Reference?.Trim().ToLowerInvariant() ?? string.Empty);
        builder.Append('|');
        builder.Append(target.Digest?.Trim().ToLowerInvariant() ?? string.Empty);
        builder.Append("|force:");
        builder.Append(force ? '1' : '0');
        builder.Append("|client:");
        builder.Append(clientRequestId?.Trim().ToLowerInvariant() ?? string.Empty);

        if (metadata is not null && metadata.Count > 0)
        {
            foreach (var pair in metadata.OrderBy(static entry => entry.Key, StringComparer.OrdinalIgnoreCase))
            {
                var key = pair.Key?.Trim().ToLowerInvariant() ?? string.Empty;
                var value = pair.Value?.Trim() ?? string.Empty;
                builder.Append('|');
                builder.Append(key);
                builder.Append('=');
                builder.Append(value);
            }
        }

        var canonical = builder.ToString();
        var hash = SHA256.HashData(Encoding.UTF8.GetBytes(canonical));
        var hex = Convert.ToHexString(hash).ToLowerInvariant();
        var trimmed = hex.Length > 40 ? hex[..40] : hex;
        return new ScanId(trimmed);
    }
}
