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

namespace ZB.MOM.WW.CBDD.Tests;

public class SetMethodTests : IDisposable
{
    private readonly TestDbContext _db;
    private readonly string _dbPath;

    /// <summary>
    ///     Initializes a new instance of the <see cref="SetMethodTests" /> class.
    /// </summary>
    public SetMethodTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"cbdd_set_{Guid.NewGuid()}.db");
        _db = new TestDbContext(_dbPath);
    }

    /// <summary>
    ///     Disposes the resources used by this instance.
    /// </summary>
    public void Dispose()
    {
        _db.Dispose();
        if (File.Exists(_dbPath)) File.Delete(_dbPath);
    }

    /// <summary>
    ///     Tests set object id returns correct collection.
    /// </summary>
    [Fact]
    public void Set_ObjectId_ReturnsCorrectCollection()
    {
        var collection = _db.Set<ObjectId, User>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.Users);
    }

    /// <summary>
    ///     Tests set shorthand returns correct collection.
    /// </summary>
    [Fact]
    public void Set_Shorthand_ReturnsCorrectCollection()
    {
        var collection = _db.Set<User>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.Users);
    }

    /// <summary>
    ///     Tests set int returns correct collection.
    /// </summary>
    [Fact]
    public void Set_Int_ReturnsCorrectCollection()
    {
        var collection = _db.Set<int, Person>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.People);
    }

    /// <summary>
    ///     Tests set string returns correct collection.
    /// </summary>
    [Fact]
    public void Set_String_ReturnsCorrectCollection()
    {
        var collection = _db.Set<string, StringEntity>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.StringEntities);
    }

    /// <summary>
    ///     Tests set guid returns correct collection.
    /// </summary>
    [Fact]
    public void Set_Guid_ReturnsCorrectCollection()
    {
        var collection = _db.Set<Guid, GuidEntity>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.GuidEntities);
    }

    /// <summary>
    ///     Tests set custom key returns correct collection.
    /// </summary>
    [Fact]
    public void Set_CustomKey_ReturnsCorrectCollection()
    {
        var collection = _db.Set<OrderId, Order>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.Orders);
    }

    /// <summary>
    ///     Tests set all object id collections return correct instances.
    /// </summary>
    [Fact]
    public void Set_AllObjectIdCollections_ReturnCorrectInstances()
    {
        _db.Set<ObjectId, AnnotatedUser>().ShouldBeSameAs(_db.AnnotatedUsers);
        _db.Set<ObjectId, ComplexUser>().ShouldBeSameAs(_db.ComplexUsers);
        _db.Set<ObjectId, TestDocument>().ShouldBeSameAs(_db.TestDocuments);
        _db.Set<ObjectId, OrderDocument>().ShouldBeSameAs(_db.OrderDocuments);
        _db.Set<ObjectId, ComplexDocument>().ShouldBeSameAs(_db.ComplexDocuments);
        _db.Set<ObjectId, PersonV2>().ShouldBeSameAs(_db.PeopleV2);
        _db.Set<ObjectId, VectorEntity>().ShouldBeSameAs(_db.VectorItems);
        _db.Set<ObjectId, GeoEntity>().ShouldBeSameAs(_db.GeoItems);
    }

    /// <summary>
    ///     Tests set all int collections return correct instances.
    /// </summary>
    [Fact]
    public void Set_AllIntCollections_ReturnCorrectInstances()
    {
        _db.Set<int, AutoInitEntity>().ShouldBeSameAs(_db.AutoInitEntities);
        _db.Set<int, Product>().ShouldBeSameAs(_db.Products);
        _db.Set<int, IntEntity>().ShouldBeSameAs(_db.IntEntities);
        _db.Set<int, AsyncDoc>().ShouldBeSameAs(_db.AsyncDocs);
        _db.Set<int, SchemaUser>().ShouldBeSameAs(_db.SchemaUsers);
    }

    /// <summary>
    ///     Tests set string key collections return correct instances.
    /// </summary>
    [Fact]
    public void Set_StringKeyCollections_ReturnCorrectInstances()
    {
        _db.Set<string, CustomKeyEntity>().ShouldBeSameAs(_db.CustomKeyEntities);
    }

    /// <summary>
    ///     Tests set unregistered entity throws invalid operation exception.
    /// </summary>
    [Fact]
    public void Set_UnregisteredEntity_ThrowsInvalidOperationException()
    {
        Should.Throw<InvalidOperationException>(() => _db.Set<ObjectId, Address>());
    }

    /// <summary>
    ///     Tests set wrong key type throws invalid operation exception.
    /// </summary>
    [Fact]
    public void Set_WrongKeyType_ThrowsInvalidOperationException()
    {
        Should.Throw<InvalidOperationException>(() => _db.Set<string, User>());
    }

    /// <summary>
    ///     Tests set can perform operations.
    /// </summary>
    [Fact]
    public void Set_CanPerformOperations()
    {
        var users = _db.Set<User>();

        var user = new User { Name = "Alice", Age = 30 };
        var id = users.Insert(user);

        var found = users.FindById(id);
        found.ShouldNotBeNull();
        found.Name.ShouldBe("Alice");
        found.Age.ShouldBe(30);
    }

    /// <summary>
    ///     Tests set with int key can perform operations.
    /// </summary>
    [Fact]
    public void Set_WithIntKey_CanPerformOperations()
    {
        var products = _db.Set<int, Product>();

        var product = new Product { Id = 1, Title = "Widget", Price = 9.99m };
        products.Insert(product);

        var found = products.FindById(1);
        found.ShouldNotBeNull();
        found.Title.ShouldBe("Widget");
        found.Price.ShouldBe(9.99m);
    }
}

public class SetMethodInheritanceTests : IDisposable
{
    private readonly TestExtendedDbContext _db;
    private readonly string _dbPath;

    /// <summary>
    ///     Initializes a new instance of the <see cref="SetMethodInheritanceTests" /> class.
    /// </summary>
    public SetMethodInheritanceTests()
    {
        _dbPath = Path.Combine(Path.GetTempPath(), $"cbdd_set_inherit_{Guid.NewGuid()}.db");
        _db = new TestExtendedDbContext(_dbPath);
    }

    /// <summary>
    ///     Disposes the resources used by this instance.
    /// </summary>
    public void Dispose()
    {
        _db.Dispose();
        if (File.Exists(_dbPath)) File.Delete(_dbPath);
    }

    /// <summary>
    ///     Tests set own collection returns correct instance.
    /// </summary>
    [Fact]
    public void Set_OwnCollection_ReturnsCorrectInstance()
    {
        var collection = _db.Set<int, ExtendedEntity>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.ExtendedEntities);
    }

    /// <summary>
    ///     Tests set parent collection returns correct instance.
    /// </summary>
    [Fact]
    public void Set_ParentCollection_ReturnsCorrectInstance()
    {
        var collection = _db.Set<ObjectId, User>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.Users);
    }

    /// <summary>
    ///     Tests set parent shorthand returns correct instance.
    /// </summary>
    [Fact]
    public void Set_ParentShorthand_ReturnsCorrectInstance()
    {
        var collection = _db.Set<User>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.Users);
    }

    /// <summary>
    ///     Tests set parent int collection returns correct instance.
    /// </summary>
    [Fact]
    public void Set_ParentIntCollection_ReturnsCorrectInstance()
    {
        _db.Set<int, Person>().ShouldBeSameAs(_db.People);
        _db.Set<int, Product>().ShouldBeSameAs(_db.Products);
    }

    /// <summary>
    ///     Tests set parent custom key returns correct instance.
    /// </summary>
    [Fact]
    public void Set_ParentCustomKey_ReturnsCorrectInstance()
    {
        var collection = _db.Set<OrderId, Order>();
        collection.ShouldNotBeNull();
        collection.ShouldBeSameAs(_db.Orders);
    }

    /// <summary>
    ///     Tests set unregistered entity throws invalid operation exception.
    /// </summary>
    [Fact]
    public void Set_UnregisteredEntity_ThrowsInvalidOperationException()
    {
        Should.Throw<InvalidOperationException>(() => _db.Set<ObjectId, Address>());
    }

    /// <summary>
    ///     Tests set own collection can perform operations.
    /// </summary>
    [Fact]
    public void Set_OwnCollection_CanPerformOperations()
    {
        var entities = _db.Set<int, ExtendedEntity>();

        var entity = new ExtendedEntity { Id = 1, Description = "Test", CreatedAt = DateTime.UtcNow };
        entities.Insert(entity);

        var found = entities.FindById(1);
        found.ShouldNotBeNull();
        found.Description.ShouldBe("Test");
    }

    /// <summary>
    ///     Tests set parent collection can perform operations.
    /// </summary>
    [Fact]
    public void Set_ParentCollection_CanPerformOperations()
    {
        var users = _db.Set<User>();

        var user = new User { Name = "Bob", Age = 25 };
        var id = users.Insert(user);

        var found = users.FindById(id);
        found.ShouldNotBeNull();
        found.Name.ShouldBe("Bob");
    }
}