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

namespace ZB.MOM.WW.CBDD.Tests;

public class HashIndexTests
{
    /// <summary>
    ///     Executes Insert_And_TryFind_Should_Return_Location.
    /// </summary>
    [Fact]
    public void Insert_And_TryFind_Should_Return_Location()
    {
        var index = new HashIndex(IndexOptions.CreateHash("age"));
        var key = IndexKey.Create(42);
        var location = new DocumentLocation(7, 3);

        index.Insert(key, location);

        index.TryFind(key, out var found).ShouldBeTrue();
        found.PageId.ShouldBe(location.PageId);
        found.SlotIndex.ShouldBe(location.SlotIndex);
    }

    /// <summary>
    ///     Executes Unique_HashIndex_Should_Throw_On_Duplicate_Key.
    /// </summary>
    [Fact]
    public void Unique_HashIndex_Should_Throw_On_Duplicate_Key()
    {
        var options = new IndexOptions
        {
            Type = IndexType.Hash,
            Unique = true,
            Fields = ["id"]
        };

        var index = new HashIndex(options);
        var key = IndexKey.Create("dup");

        index.Insert(key, new DocumentLocation(1, 1));

        Should.Throw<InvalidOperationException>(() =>
            index.Insert(key, new DocumentLocation(2, 2)));
    }

    /// <summary>
    ///     Executes Remove_Should_Remove_Only_Matching_Entry.
    /// </summary>
    [Fact]
    public void Remove_Should_Remove_Only_Matching_Entry()
    {
        var index = new HashIndex(IndexOptions.CreateHash("name"));
        var key = IndexKey.Create("john");
        var location1 = new DocumentLocation(10, 1);
        var location2 = new DocumentLocation(11, 2);

        index.Insert(key, location1);
        index.Insert(key, location2);

        index.Remove(key, location1).ShouldBeTrue();
        index.Remove(key, location1).ShouldBeFalse();

        var remaining = index.FindAll(key).ToList();
        remaining.Count.ShouldBe(1);
        remaining[0].Location.PageId.ShouldBe(location2.PageId);
        remaining[0].Location.SlotIndex.ShouldBe(location2.SlotIndex);

        index.Remove(key, location2).ShouldBeTrue();
        index.FindAll(key).ShouldBeEmpty();
    }

    /// <summary>
    ///     Executes FindAll_Should_Return_All_Matching_Entries.
    /// </summary>
    [Fact]
    public void FindAll_Should_Return_All_Matching_Entries()
    {
        var index = new HashIndex(IndexOptions.CreateHash("score"));
        var key = IndexKey.Create(99);

        index.Insert(key, new DocumentLocation(1, 0));
        index.Insert(key, new DocumentLocation(2, 0));
        index.Insert(IndexKey.Create(100), new DocumentLocation(3, 0));

        var matches = index.FindAll(key).ToList();

        matches.Count.ShouldBe(2);
        matches.All(e => e.Key == key).ShouldBeTrue();
    }
}