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

namespace ZB.MOM.WW.CBDD.Tests;

public class StorageEngineDictionaryTests
{
    private string GetTempDbPath()
    {
        return Path.Combine(Path.GetTempPath(), $"test_storage_dict_{Guid.NewGuid()}.db");
    }

    private void Cleanup(string path)
    {
        if (File.Exists(path)) File.Delete(path);
        if (File.Exists(Path.ChangeExtension(path, ".wal"))) File.Delete(Path.ChangeExtension(path, ".wal"));
    }

    /// <summary>
    ///     Verifies dictionary pages are initialized and return normalized keys.
    /// </summary>
    [Fact]
    public void StorageEngine_ShouldInitializeDictionary()
    {
        string path = GetTempDbPath();
        try
        {
            using (var storage = new StorageEngine(path, PageFileConfig.Default))
            {
                // Should generate ID > 100
                ushort id = storage.GetOrAddDictionaryEntry("TestKey");
                (id > DictionaryPage.ReservedValuesEnd).ShouldBeTrue();

                string? key = storage.GetDictionaryKey(id);
                key.ShouldBe("testkey");
            }
        }
        finally
        {
            Cleanup(path);
        }
    }

    /// <summary>
    ///     Verifies dictionary entries persist across reopen.
    /// </summary>
    [Fact]
    public void StorageEngine_ShouldPersistDictionary()
    {
        string path = GetTempDbPath();
        try
        {
            ushort id1, id2;
            using (var storage = new StorageEngine(path, PageFileConfig.Default))
            {
                id1 = storage.GetOrAddDictionaryEntry("Key1");
                id2 = storage.GetOrAddDictionaryEntry("Key2");
            }

            // Reopen
            using (var storage = new StorageEngine(path, PageFileConfig.Default))
            {
                ushort val1 = storage.GetOrAddDictionaryEntry("Key1");
                ushort val2 = storage.GetOrAddDictionaryEntry("Key2");

                val1.ShouldBe(id1);
                val2.ShouldBe(id2);

                storage.GetDictionaryKey(val1).ShouldBe("key1");
                storage.GetDictionaryKey(val2).ShouldBe("key2");
            }
        }
        finally
        {
            Cleanup(path);
        }
    }

    /// <summary>
    ///     Verifies dictionary handling scales to many keys and remains durable.
    /// </summary>
    [Fact]
    public void StorageEngine_ShouldHandleManyKeys()
    {
        string path = GetTempDbPath();
        try
        {
            const int keyCount = 3000;
            var expectedIds = new Dictionary<string, ushort>();

            using (var storage = new StorageEngine(path, PageFileConfig.Default))
            {
                for (var i = 0; i < keyCount; i++)
                {
                    var key = $"Key_{i}";
                    ushort id = storage.GetOrAddDictionaryEntry(key);
                    expectedIds[key] = id;
                }
            }

            // Reopen and Verify
            using (var storage = new StorageEngine(path, PageFileConfig.Default))
            {
                for (var i = 0; i < keyCount; i++)
                {
                    var key = $"Key_{i}";
                    ushort id = storage.GetOrAddDictionaryEntry(key); // Should get existing
                    id.ShouldBe(expectedIds[key]);

                    string? loadedKey = storage.GetDictionaryKey(id);
                    loadedKey.ShouldBe(key.ToLowerInvariant());
                }

                // Add new one
                ushort newId = storage.GetOrAddDictionaryEntry("NewKeyAfterReopen");
                (newId > 0).ShouldBeTrue();
                expectedIds.ContainsValue(newId).ShouldBeFalse();
            }
        }
        finally
        {
            Cleanup(path);
        }
    }
}