using System.Security.Cryptography;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;

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

/// <summary>
/// Builds a <see cref="BundleManifest"/> for a freshly serialized bundle.
/// Stamps the current format/schema version, captures the SHA-256 hash of the
/// raw (post-encryption) content bytes, and copies through the supplied summary
/// and content entries verbatim.
/// </summary>
public sealed class ManifestBuilder
{
    public const int CurrentBundleFormatVersion = 1;

    // Schema minor version. Bumped 1.0 → 1.1 to carry the additive
    // site/dataConnection/instance summary counts (and their content arrays).
    // Minor bumps are additive-only: ManifestValidator gates solely on
    // BundleFormatVersion, so an older "1.0" bundle still validates Ok.
    public const string CurrentSchemaVersion = "1.1";

    /// <summary>
    /// Builds a <see cref="BundleManifest"/> with the current format version, a SHA-256 content hash,
    /// and all supplied metadata.
    /// </summary>
    /// <param name="sourceEnvironment">Environment label identifying where the bundle was exported from.</param>
    /// <param name="exportedBy">Username of the operator who performed the export.</param>
    /// <param name="scadaBridgeVersion">ScadaBridge version string stamped in the manifest.</param>
    /// <param name="encryption">Encryption metadata when the content is encrypted; null for plain bundles.</param>
    /// <param name="summary">High-level summary of artifact counts.</param>
    /// <param name="contents">Per-entry content table describing each artifact in the bundle.</param>
    /// <param name="contentBytes">Raw content bytes whose SHA-256 hash is computed and stamped.</param>
    /// <returns>A fully populated <see cref="BundleManifest"/>.</returns>
    public BundleManifest Build(
        string sourceEnvironment,
        string exportedBy,
        string scadaBridgeVersion,
        EncryptionMetadata? encryption,
        BundleSummary summary,
        IReadOnlyList<ManifestContentEntry> contents,
        byte[] contentBytes)
    {
        ArgumentNullException.ThrowIfNull(sourceEnvironment);
        ArgumentNullException.ThrowIfNull(exportedBy);
        ArgumentNullException.ThrowIfNull(scadaBridgeVersion);
        ArgumentNullException.ThrowIfNull(summary);
        ArgumentNullException.ThrowIfNull(contents);
        ArgumentNullException.ThrowIfNull(contentBytes);

        var contentHash = "sha256:" + Convert.ToHexString(SHA256.HashData(contentBytes)).ToLowerInvariant();

        return new BundleManifest(
            BundleFormatVersion: CurrentBundleFormatVersion,
            SchemaVersion: CurrentSchemaVersion,
            CreatedAtUtc: DateTimeOffset.UtcNow,
            SourceEnvironment: sourceEnvironment,
            ExportedBy: exportedBy,
            ScadaBridgeVersion: scadaBridgeVersion,
            ContentHash: contentHash,
            Encryption: encryption,
            Summary: summary,
            Contents: contents);
    }
}
