using Microsoft.EntityFrameworkCore;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase;
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Configurations;

namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests.Configurations;

/// <summary>
/// Schema-level tests for <see cref="SiteCallEntityTypeConfiguration"/> (#22 / #23 M3 Bundle B).
/// Verifies the <see cref="SiteCall"/> record maps to the <c>SiteCalls</c> table with the
/// expected primary key, value conversion on <c>TrackedOperationId</c>, and the two named
/// indexes that back the "calls from this site" and "calls in this status" Central UI queries.
/// Mirrors the AuditLog Bundle B test pattern — inspects EF model metadata via the existing
/// in-memory SQLite test context, no database round-trips required.
/// </summary>
public class SiteCallEntityTypeConfigurationTests : IDisposable
{
    private readonly ScadaBridgeDbContext _context;

    public SiteCallEntityTypeConfigurationTests()
    {
        _context = SqliteTestHelper.CreateInMemoryContext();
    }

    public void Dispose()
    {
        _context.Database.CloseConnection();
        _context.Dispose();
    }

    [Fact]
    public void Configure_MapsToSiteCallsTable()
    {
        var entity = _context.Model.FindEntityType(typeof(SiteCall));

        Assert.NotNull(entity);
        Assert.Equal("SiteCalls", entity!.GetTableName());
    }

    [Fact]
    public void Configure_PrimaryKey_TrackedOperationId()
    {
        var entity = _context.Model.FindEntityType(typeof(SiteCall));
        Assert.NotNull(entity);

        var pk = entity!.FindPrimaryKey();
        Assert.NotNull(pk);

        var pkPropertyNames = pk!.Properties.Select(p => p.Name).ToArray();
        Assert.Equal(new[] { nameof(SiteCall.TrackedOperationId) }, pkPropertyNames);
    }

    [Fact]
    public void Configure_HasIndexes_NamedAndOrdered()
    {
        var entity = _context.Model.FindEntityType(typeof(SiteCall));
        Assert.NotNull(entity);

        var indexes = entity!.GetIndexes().ToList();

        // IX_SiteCalls_Source_Created: (SourceSite ASC, CreatedAtUtc DESC).
        var sourceCreated = indexes.SingleOrDefault(i => i.GetDatabaseName() == "IX_SiteCalls_Source_Created");
        Assert.NotNull(sourceCreated);
        var sourceCreatedProps = sourceCreated!.Properties.Select(p => p.Name).ToArray();
        Assert.Equal(new[] { nameof(SiteCall.SourceSite), nameof(SiteCall.CreatedAtUtc) }, sourceCreatedProps);

        // IX_SiteCalls_Status_Updated: (Status ASC, UpdatedAtUtc DESC).
        var statusUpdated = indexes.SingleOrDefault(i => i.GetDatabaseName() == "IX_SiteCalls_Status_Updated");
        Assert.NotNull(statusUpdated);
        var statusUpdatedProps = statusUpdated!.Properties.Select(p => p.Name).ToArray();
        Assert.Equal(new[] { nameof(SiteCall.Status), nameof(SiteCall.UpdatedAtUtc) }, statusUpdatedProps);
    }

    [Fact]
    public void Configure_TrackedOperationId_ConvertedToString_Length36()
    {
        var entity = _context.Model.FindEntityType(typeof(SiteCall));
        Assert.NotNull(entity);

        var property = entity!.FindProperty(nameof(SiteCall.TrackedOperationId));
        Assert.NotNull(property);

        // Stored as varchar(36) (TrackedOperationId.ToString("D") is always 36 chars).
        // The value-conversion target type is exposed via GetProviderClrType when set, or
        // discovered indirectly through the configured converter; either way the on-wire
        // CLR type is string.
        var providerClrType = property!.GetProviderClrType() ?? property.GetValueConverter()?.ProviderClrType;
        Assert.Equal(typeof(string), providerClrType);
        Assert.Equal(36, property.GetMaxLength());
        Assert.False(property.IsUnicode() ?? true);
    }

    [Theory]
    [InlineData(nameof(SiteCall.Channel), 32)]
    [InlineData(nameof(SiteCall.SourceSite), 64)]
    [InlineData(nameof(SiteCall.Status), 32)]
    [InlineData(nameof(SiteCall.Target), 256)]
    public void Configure_AsciiBoundedColumns(string propertyName, int expectedMaxLength)
    {
        var entity = _context.Model.FindEntityType(typeof(SiteCall));
        Assert.NotNull(entity);

        var property = entity!.FindProperty(propertyName);
        Assert.NotNull(property);

        Assert.Equal(expectedMaxLength, property!.GetMaxLength());
        Assert.False(property.IsUnicode() ?? true);
    }
}
