using System.Buffers.Binary;
using ZB.MOM.WW.CBDD.Core.Compression;

namespace ZB.MOM.WW.CBDD.Core.Storage;

[Flags]
internal enum StorageFeatureFlags : byte
{
    None = 0,
    CompressionCapability = 1 << 0
}

internal readonly struct StorageFormatMetadata
{
    internal const int WireSize = 16;

    /// <summary>
    ///     Gets a value indicating whether format metadata is present.
    /// </summary>
    public bool IsPresent { get; }

    /// <summary>
    ///     Gets the storage format version.
    /// </summary>
    public byte Version { get; }

    /// <summary>
    ///     Gets enabled storage feature flags.
    /// </summary>
    public StorageFeatureFlags FeatureFlags { get; }

    /// <summary>
    ///     Gets the default compression codec.
    /// </summary>
    public CompressionCodec DefaultCodec { get; }

    /// <summary>
    ///     Gets a value indicating whether compression capability is enabled.
    /// </summary>
    public bool CompressionCapabilityEnabled => (FeatureFlags & StorageFeatureFlags.CompressionCapability) != 0;

    private StorageFormatMetadata(bool isPresent, byte version, StorageFeatureFlags featureFlags,
        CompressionCodec defaultCodec)
    {
        IsPresent = isPresent;
        Version = version;
        FeatureFlags = featureFlags;
        DefaultCodec = defaultCodec;
    }

    /// <summary>
    ///     Creates metadata representing a modern format-aware file.
    /// </summary>
    /// <param name="version">The storage format version.</param>
    /// <param name="featureFlags">Enabled feature flags.</param>
    /// <param name="defaultCodec">The default compression codec.</param>
    public static StorageFormatMetadata Present(byte version, StorageFeatureFlags featureFlags,
        CompressionCodec defaultCodec)
    {
        return new StorageFormatMetadata(true, version, featureFlags, defaultCodec);
    }

    /// <summary>
    ///     Creates metadata representing a legacy file without format metadata.
    /// </summary>
    /// <param name="defaultCodec">The default compression codec.</param>
    public static StorageFormatMetadata Legacy(CompressionCodec defaultCodec)
    {
        return new StorageFormatMetadata(false, 0, StorageFeatureFlags.None, defaultCodec);
    }
}

internal static class StorageFormatConstants
{
    internal const ushort SlottedPageFormatMarker = 0x4301;
}

public sealed partial class StorageEngine
{
    private const int StorageHeaderExtensionOffset = 0;
    private const uint StorageFormatMagic = 0x4D464243u; // "CBFM" little-endian
    private const byte CurrentStorageFormatVersion = 1;

    private StorageFormatMetadata InitializeStorageFormatMetadata()
    {
        Span<byte> metadataBuffer = stackalloc byte[StorageFormatMetadata.WireSize];
        _pageFile.ReadPageZeroExtension(StorageHeaderExtensionOffset, metadataBuffer);

        if (TryReadStorageFormatMetadata(metadataBuffer, out var metadata))
            return metadata;

        if (!_pageFile.WasCreated)
            return StorageFormatMetadata.Legacy(CompressionOptions.Codec);

        var featureFlags = CompressionOptions.EnableCompression
            ? StorageFeatureFlags.CompressionCapability
            : StorageFeatureFlags.None;
        var initialMetadata =
            StorageFormatMetadata.Present(CurrentStorageFormatVersion, featureFlags, CompressionOptions.Codec);
        WriteStorageFormatMetadata(initialMetadata);
        return initialMetadata;
    }

    private static bool TryReadStorageFormatMetadata(ReadOnlySpan<byte> source, out StorageFormatMetadata metadata)
    {
        metadata = default;
        if (source.Length < StorageFormatMetadata.WireSize)
            return false;

        uint magic = BinaryPrimitives.ReadUInt32LittleEndian(source.Slice(0, 4));
        if (magic != StorageFormatMagic)
            return false;

        byte version = source[4];
        var featureFlags = (StorageFeatureFlags)source[5];
        var codec = (CompressionCodec)source[6];
        if (!Enum.IsDefined(codec))
            codec = CompressionCodec.None;

        metadata = StorageFormatMetadata.Present(version, featureFlags, codec);
        return true;
    }

    private void WriteStorageFormatMetadata(StorageFormatMetadata metadata)
    {
        Span<byte> buffer = stackalloc byte[StorageFormatMetadata.WireSize];
        buffer.Clear();
        BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(0, 4), StorageFormatMagic);
        buffer[4] = metadata.Version;
        buffer[5] = (byte)metadata.FeatureFlags;
        buffer[6] = (byte)metadata.DefaultCodec;
        _pageFile.WritePageZeroExtension(StorageHeaderExtensionOffset, buffer);
    }
}