using ZB.MOM.WW.CBDD.Bson;
using ZB.MOM.WW.CBDD.Core.Collections;
using ZB.MOM.WW.CBDD.Core.Indexing;
using ZB.MOM.WW.CBDD.Core.Storage;
using ZB.MOM.WW.CBDD.Core.Transactions;
using ZB.MOM.WW.CBDD.Shared;
using ZB.MOM.WW.CBDD.Shared.TestDbContext_TestDbContext_Mappers;
using Xunit;

namespace ZB.MOM.WW.CBDD.Tests;

public class MetadataPersistenceTests : IDisposable
{
    private readonly string _dbPath;
    private readonly string _walPath;

    public MetadataPersistenceTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"docdb_meta_{Guid.NewGuid()}.db");
        _walPath = Path.ChangeExtension(_dbPath, ".wal");
    }

    [Fact]
    public void IndexDefinitions_ArePersisted_AndReloaded()
    {
        // 1. Create index in first session
        using (var storage = new StorageEngine(_dbPath, PageFileConfig.Default))
        {
            // Disable auto-checkpoint to ensure cleaner test tracing, though not strictly required
            var mapper = new ZB_MOM_WW_CBDD_Shared_UserMapper();
            var indexManager = new CollectionIndexManager<ObjectId, User>(storage, mapper, nameof(User));

            // Create 2 indexes
            indexManager.CreateIndex(u => u.Age, "idx_age");
            indexManager.CreateIndex(u => u.Name, unique: true); // name auto-generated
        }

        // 2. Re-open storage and verify indexes exist
        using (var storage = new StorageEngine(_dbPath, PageFileConfig.Default))
        {
            var mapper = new ZB_MOM_WW_CBDD_Shared_UserMapper();
            // Assuming Page 1 was allocated above in clean DB
            var indexManager = new CollectionIndexManager<ObjectId, User>(storage, mapper, nameof(User));

            var indexes = indexManager.GetAllIndexes().ToList();

            indexes.Count.ShouldBe(2);

            var ageIdx = indexManager.GetIndex("idx_age");
            ageIdx.ShouldNotBeNull();
            ageIdx.Definition.IsUnique.ShouldBeFalse();
            ageIdx.Definition.PropertyPaths.Count().ShouldBe(1);
            ageIdx.Definition.PropertyPaths[0].ShouldBe("Age");

            // Check auto-generated name index
            var nameIdx = indexes.FirstOrDefault(i => i.Definition.PropertyPaths[0] == "Name");
            nameIdx.ShouldNotBeNull();
            nameIdx.Definition.IsUnique.ShouldBeTrue();
        }
    }

    [Fact]
    public void EnsureIndex_DoesNotRecreate_IfIndexExists()
    {
        // 1. Create index
        using (var context = new Shared.TestDbContext(_dbPath))
        {
            context.Users.EnsureIndex(u => u.Age);
        }

        // 2. Re-open and EnsureIndex again - should be fast/no-op
        using (var context = new Shared.TestDbContext(_dbPath))
        {
            var mapper = new ZB_MOM_WW_CBDD_Shared_UserMapper();

            // Use reflection or diagnostic to check if it triggered rebuild?
            // Currently hard to verify "no rebuild" without logs or mocking.
            // But we can verify it doesn't throw and index is still valid.

            var idx = context.Users.EnsureIndex(u => u.Age);
            idx.ShouldNotBeNull();

            // Verify functioning
            using var txn = context.BeginTransaction();
            context.Users.Insert(new User { Name = "Bob", Age = 50 });
            txn.Commit();

            // Should find it via index
            var results = context.Users.Find(u => u.Age == 50).ToList();
            results.Count().ShouldBe(1);
        }
    }

    public void Dispose()
    {
        if (File.Exists(_dbPath)) File.Delete(_dbPath);
        if (File.Exists(_walPath)) File.Delete(_walPath);
    }
}
