using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using ScadaLink.Commons.Entities.Deployment;
using ScadaLink.ConfigurationDatabase;

namespace ScadaLink.ConfigurationDatabase.Tests;

/// <summary>
/// Test DbContext that adapts SQL Server-specific features for SQLite:
/// - Maps DateTimeOffset to sortable ISO 8601 strings (SQLite has no native DateTimeOffset ORDER BY)
/// - Replaces SQL Server RowVersion with a nullable byte[] column (SQLite can't auto-generate rowversion)
/// </summary>
public class SqliteTestDbContext : ScadaLinkDbContext
{
    public SqliteTestDbContext(DbContextOptions<ScadaLinkDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // SQLite cannot auto-generate SQL Server rowversion values.
        // Replace with a nullable byte[] column so inserts don't fail with NOT NULL constraint.
        modelBuilder.Entity<DeploymentRecord>(builder =>
        {
            builder.Property(d => d.RowVersion)
                .IsRequired(false)
                .IsConcurrencyToken(false)
                .ValueGeneratedNever();
        });

        // Convert DateTimeOffset to ISO 8601 string for SQLite so ORDER BY works
        var converter = new ValueConverter<DateTimeOffset, string>(
            v => v.UtcDateTime.ToString("o"),
            v => DateTimeOffset.Parse(v));

        var nullableConverter = new ValueConverter<DateTimeOffset?, string?>(
            v => v.HasValue ? v.Value.UtcDateTime.ToString("o") : null,
            v => v != null ? DateTimeOffset.Parse(v) : null);

        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            foreach (var property in entityType.GetProperties())
            {
                if (property.ClrType == typeof(DateTimeOffset))
                {
                    property.SetValueConverter(converter);
                    property.SetColumnType("TEXT");
                }
                else if (property.ClrType == typeof(DateTimeOffset?))
                {
                    property.SetValueConverter(nullableConverter);
                    property.SetColumnType("TEXT");
                }
            }
        }
    }
}

public static class SqliteTestHelper
{
    public static ScadaLinkDbContext CreateInMemoryContext()
    {
        var options = new DbContextOptionsBuilder<ScadaLinkDbContext>()
            .UseSqlite("DataSource=:memory:")
            .ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))
            .Options;

        var context = new SqliteTestDbContext(options);
        context.Database.OpenConnection();
        context.Database.EnsureCreated();
        return context;
    }

    public static ScadaLinkDbContext CreateFileContext(string dbPath)
    {
        var options = new DbContextOptionsBuilder<ScadaLinkDbContext>()
            .UseSqlite($"DataSource={dbPath}")
            .ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))
            .Options;

        var context = new SqliteTestDbContext(options);
        return context;
    }
}
