using ZB.MOM.WW.CBDD.Bson;
using ZB.MOM.WW.CBDD.Shared;

namespace ZB.MOM.WW.CBDD.Tests;

public class BulkOperationsTests : IDisposable
{
    private readonly TestDbContext _dbContext;
    private readonly string _dbPath;
    private readonly string _walPath;

    /// <summary>
    ///     Initializes a new instance of the <see cref="BulkOperationsTests" /> class.
    /// </summary>
    public BulkOperationsTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"test_bulk_{Guid.NewGuid()}.db");
        _walPath = Path.Combine(Path.GetTempPath(), $"test_bulk_{Guid.NewGuid()}.wal");

        _dbContext = new TestDbContext(_dbPath);
    }

    /// <summary>
    ///     Executes Dispose.
    /// </summary>
    public void Dispose()
    {
        _dbContext.Dispose();
    }

    /// <summary>
    ///     Executes UpdateBulk_UpdatesMultipleDocuments.
    /// </summary>
    [Fact]
    public void UpdateBulk_UpdatesMultipleDocuments()
    {
        // Arrange: Insert 100 users
        var users = new List<User>();
        for (var i = 0; i < 100; i++) users.Add(new User { Id = ObjectId.NewObjectId(), Name = $"User {i}", Age = 20 });
        _dbContext.Users.InsertBulk(users);
        _dbContext.SaveChanges();

        // Modify users
        foreach (var u in users)
        {
            u.Age = 30; // In-place update (int is same size)
            if (u.Name.EndsWith("0")) u.Name += "_Modified_Longer"; // Force move update
        }

        // Act
        int updatedCount = _dbContext.Users.UpdateBulk(users);
        _dbContext.SaveChanges();

        // Assert
        updatedCount.ShouldBe(100);

        // Verify changes
        foreach (var u in users)
        {
            var stored = _dbContext.Users.FindById(u.Id);
            stored.ShouldNotBeNull();
            stored.Age.ShouldBe(30);
            stored.Name.ShouldBe(u.Name);
        }
    }

    /// <summary>
    ///     Executes DeleteBulk_RemovesMultipleDocuments.
    /// </summary>
    [Fact]
    public void DeleteBulk_RemovesMultipleDocuments()
    {
        // Arrange: Insert 100 users
        var users = new List<User>();
        for (var i = 0; i < 100; i++) users.Add(new User { Id = ObjectId.NewObjectId(), Name = $"User {i}", Age = 20 });
        _dbContext.Users.InsertBulk(users);
        _dbContext.SaveChanges();

        var idsToDelete = users.Take(50).Select(u => u.Id).ToList();

        // Act
        int deletedCount = _dbContext.Users.DeleteBulk(idsToDelete);
        _dbContext.SaveChanges();

        // Assert
        deletedCount.ShouldBe(50);

        // Verify deleted
        foreach (var id in idsToDelete) _dbContext.Users.FindById(id).ShouldBeNull();

        // Verify remaining
        var remaining = users.Skip(50).ToList();
        foreach (var u in remaining) _dbContext.Users.FindById(u.Id).ShouldNotBeNull();

        // Verify count
        // Note: Count() is not fully implemented efficiently yet (iterates everything), but FindAll().Count() works
        _dbContext.Users.FindAll().Count().ShouldBe(50);
    }

    /// <summary>
    ///     Executes DeleteBulk_WithTransaction_Rollworks.
    /// </summary>
    [Fact]
    public void DeleteBulk_WithTransaction_Rollworks()
    {
        // Arrange
        var user = new User { Id = ObjectId.NewObjectId(), Name = "Txn User", Age = 20 };
        _dbContext.Users.Insert(user);
        _dbContext.SaveChanges();

        _dbContext.Users.FindById(user.Id).ShouldNotBeNull();

        using (var txn = _dbContext.BeginTransaction())
        {
            _dbContext.Users.DeleteBulk(new[] { user.Id });
            txn.Rollback();
        }

        // Assert: Should still exist
        _dbContext.Users.FindById(user.Id).ShouldNotBeNull();
    }
}