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

namespace ZB.MOM.WW.CBDD.Tests;

public class BTreeDeleteUnderflowTests
{
    /// <summary>
    /// Executes Delete_HeavyWorkload_Should_Remain_Queryable_After_Merges.
    /// </summary>
    [Fact]
    public void Delete_HeavyWorkload_Should_Remain_Queryable_After_Merges()
    {
        var dbPath = Path.Combine(Path.GetTempPath(), $"btree_underflow_{Guid.NewGuid():N}.db");

        try
        {
            using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
            var index = new BTreeIndex(storage, IndexOptions.CreateBTree("k"));

            var insertTxn = storage.BeginTransaction().TransactionId;
            for (int i = 1; i <= 240; i++)
            {
                index.Insert(IndexKey.Create(i), new DocumentLocation((uint)(1000 + i), 0), insertTxn);
            }
            storage.CommitTransaction(insertTxn);

            var deleteTxn = storage.BeginTransaction().TransactionId;
            for (int i = 1; i <= 190; i++)
            {
                index.Delete(IndexKey.Create(i), new DocumentLocation((uint)(1000 + i), 0), deleteTxn).ShouldBeTrue();
            }
            storage.CommitTransaction(deleteTxn);

            for (int i = 1; i <= 190; i++)
            {
                index.TryFind(IndexKey.Create(i), out _, 0).ShouldBeFalse();
            }

            for (int i = 191; i <= 240; i++)
            {
                index.TryFind(IndexKey.Create(i), out var location, 0).ShouldBeTrue();
                location.PageId.ShouldBe((uint)(1000 + i));
            }

            var remaining = index.GreaterThan(IndexKey.Create(190), orEqual: false, 0).ToList();
            remaining.Count.ShouldBe(50);
            remaining.First().Key.ShouldBe(IndexKey.Create(191));
            remaining.Last().Key.ShouldBe(IndexKey.Create(240));
        }
        finally
        {
            if (File.Exists(dbPath)) File.Delete(dbPath);
            var walPath = Path.ChangeExtension(dbPath, ".wal");
            if (File.Exists(walPath)) File.Delete(walPath);
        }
    }
}
