// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Extensions.VectorData;
using SqliteVec.ConformanceTests.Support;
using VectorData.ConformanceTests;
using VectorData.ConformanceTests.Support;
using Xunit;
using Xunit.Sdk;

namespace SqliteVec.ConformanceTests;

#pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast

public class SqliteFilterTests(SqliteFilterTests.Fixture fixture)
    : FilterTests<long>(fixture), IClassFixture<SqliteFilterTests.Fixture>
{
    public override async Task Not_over_Or()
    {
        // Test sends: WHERE (NOT (("Int" = 8) OR ("String" = 'foo')))
        // There's a NULL string in the database, and relational null semantics in conjunction with negation makes the default implementation fail.
        await Assert.ThrowsAsync<FailException>(base.Not_over_Or);

        // Compensate by adding a null check:
        await this.TestFilterAsync(
            r => r.String != null && !(r.Int == 8 || r.String == "foo"),
            r => r["String"] != null && !((int)r["Int"]! == 8 || r["String"] == "foo"));
    }

    public override async Task NotEqual_with_string()
    {
        // As above, null semantics + negation
        await Assert.ThrowsAsync<FailException>(base.NotEqual_with_string);

        await this.TestFilterAsync(
            r => r.String != null && r.String != "foo",
            r => r["String"] != null && r["String"] != "foo");
    }

    // Array fields not (currently) supported on SQLite (see #10343)
    public override Task Contains_over_field_string_array()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Contains_over_field_string_array);

    // List fields not (currently) supported on SQLite (see #10343)
    public override Task Contains_over_field_string_List()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Contains_over_field_string_List);

    // List fields not (currently) supported on SQLite (see #10343)
    public override Task Contains_with_Enumerable_Contains()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Contains_with_Enumerable_Contains);

#if !NETFRAMEWORK
    // List fields not (currently) supported on SQLite (see #10343)
    public override Task Contains_with_MemoryExtensions_Contains()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Contains_with_MemoryExtensions_Contains);
#endif

#if NET10_0_OR_GREATER
    public override Task Contains_with_MemoryExtensions_Contains_with_null_comparer()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Contains_with_MemoryExtensions_Contains_with_null_comparer);
#endif

    // Any over array fields not (currently) supported on SQLite (see #10343)
    public override Task Any_with_Contains_over_inline_string_array()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Any_with_Contains_over_inline_string_array);

    public override Task Any_with_Contains_over_captured_string_array()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Any_with_Contains_over_captured_string_array);

    public override Task Any_with_Contains_over_captured_string_list()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Any_with_Contains_over_captured_string_list);

    public override Task Any_over_List_with_Contains_over_captured_string_array()
        => Assert.ThrowsAsync<InvalidOperationException>(base.Any_over_List_with_Contains_over_captured_string_array);

    public new class Fixture : FilterTests<long>.Fixture
    {
        public override TestStore TestStore => SqliteTestStore.Instance;

        // Override to remove the string array property, which isn't (currently) supported on SQLite
        public override VectorStoreCollectionDefinition CreateRecordDefinition()
            => new()
            {
                Properties = base.CreateRecordDefinition().Properties.Where(p => p.Type != typeof(string[]) && p.Type != typeof(List<string>)).ToList()
            };
    }
}
