using Jiaowu.Api.Infrastructure.Observability;
using Jiaowu.Api.Infrastructure.Persistence;
using Microsoft.AspNetCore.Http;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;

namespace Jiaowu.Api.Tests;

public sealed class DatabaseCommandTelemetryInterceptorTests
{
    [Fact]
    public void Query_name_uses_tag_without_exposing_statement_text()
    {
        const string sql =
            "-- Timetable.LoadMixedExamEntries\n" +
            "SELECT * FROM ExamRooms WHERE SecretValue = @p0";

        var queryName =
            DatabaseCommandTelemetryInterceptor.GetQueryName(sql);

        Assert.Equal("Timetable.LoadMixedExamEntries", queryName);
        Assert.DoesNotContain("SecretValue", queryName);
        Assert.DoesNotContain("@p0", queryName);
    }

    [Fact]
    public void Untagged_query_name_is_stable_hash_not_statement_text()
    {
        const string sql =
            "SELECT * FROM Students WHERE StudentNumber = @studentNumber";

        var first = DatabaseCommandTelemetryInterceptor.GetQueryName(sql);
        var second = DatabaseCommandTelemetryInterceptor.GetQueryName(sql);

        Assert.Equal(first, second);
        Assert.StartsWith("select:", first);
        Assert.DoesNotContain("Students", first);
        Assert.DoesNotContain("StudentNumber", first);
    }

    [Fact]
    public async Task Ef_command_executes_with_logging_interceptor()
    {
        await using var connection =
            new SqliteConnection("Data Source=:memory:");
        await connection.OpenAsync();

        var setupOptions = new DbContextOptionsBuilder<AppDbContext>()
            .UseSqlite(connection)
            .Options;
        await using (var setupDb = new AppDbContext(setupOptions))
            await setupDb.Database.EnsureCreatedAsync();

        var interceptor = new DatabaseCommandTelemetryInterceptor(
            new ObservabilityOptions(),
            new HttpContextAccessor(),
            NullLogger<DatabaseCommandTelemetryInterceptor>.Instance);
        var queryOptions = new DbContextOptionsBuilder<AppDbContext>()
            .UseSqlite(connection)
            .AddInterceptors(interceptor)
            .Options;
        await using var db = new AppDbContext(queryOptions);

        await db.AcademicTerms
            .TagWith("Observability.Tests.TermCount")
            .CountAsync();

        Assert.Equal(0, await db.AcademicTerms.CountAsync());
    }
}
