using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ScadaLink.Commons.Entities.Audit;

namespace ScadaLink.ConfigurationDatabase.Configurations;

/// <summary>
/// Maps the <see cref="AuditEvent"/> record to the central <c>AuditLog</c> table
/// described in alog.md §4. Column lengths/types and the five named indexes are
/// fixed by that specification — keep this in sync with the doc.
/// </summary>
public class AuditLogEntityTypeConfiguration : IEntityTypeConfiguration<AuditEvent>
{
    public void Configure(EntityTypeBuilder<AuditEvent> builder)
    {
        builder.ToTable("AuditLog");

        // Composite PK includes OccurredAtUtc — required by the monthly partition scheme
        // (ps_AuditLog_Month) so the clustered key is partition-aligned. EventId still
        // needs to be globally unique for InsertIfNotExistsAsync idempotency, so a
        // separate unique index is declared on EventId alone.
        builder.HasKey(e => new { e.EventId, e.OccurredAtUtc });

        builder.HasIndex(e => e.EventId)
            .IsUnique()
            .HasDatabaseName("UX_AuditLog_EventId");

        // Enum-as-string columns: bounded varchar(32) ASCII.
        builder.Property(e => e.Channel)
            .HasConversion<string>()
            .HasMaxLength(32)
            .IsUnicode(false)
            .IsRequired();

        builder.Property(e => e.Kind)
            .HasConversion<string>()
            .HasMaxLength(32)
            .IsUnicode(false)
            .IsRequired();

        builder.Property(e => e.Status)
            .HasConversion<string>()
            .HasMaxLength(32)
            .IsUnicode(false)
            .IsRequired();

        builder.Property(e => e.ForwardState)
            .HasConversion<string>()
            .HasMaxLength(32)
            .IsUnicode(false);

        // Ascii identifier columns — never carry user-supplied unicode.
        builder.Property(e => e.SourceSiteId)
            .HasMaxLength(64)
            .IsUnicode(false);

        builder.Property(e => e.SourceInstanceId)
            .HasMaxLength(128)
            .IsUnicode(false);

        builder.Property(e => e.SourceScript)
            .HasMaxLength(128)
            .IsUnicode(false);

        builder.Property(e => e.Actor)
            .HasMaxLength(128)
            .IsUnicode(false);

        builder.Property(e => e.Target)
            .HasMaxLength(256)
            .IsUnicode(false);

        // Bounded unicode message column.
        builder.Property(e => e.ErrorMessage)
            .HasMaxLength(1024);

        // ErrorDetail, RequestSummary, ResponseSummary, Extra: leave as nvarchar(max).

        // Indexes — names locked to alog.md §4 for reconciliation/migration discoverability.
        builder.HasIndex(e => e.OccurredAtUtc)
            .IsDescending(true)
            .HasDatabaseName("IX_AuditLog_OccurredAtUtc");

        builder.HasIndex(e => new { e.SourceSiteId, e.OccurredAtUtc })
            .IsDescending(false, true)
            .HasDatabaseName("IX_AuditLog_Site_Occurred");

        builder.HasIndex(e => e.CorrelationId)
            .HasFilter("[CorrelationId] IS NOT NULL")
            .HasDatabaseName("IX_AuditLog_CorrelationId");

        builder.HasIndex(e => new { e.Channel, e.Status, e.OccurredAtUtc })
            .IsDescending(false, false, true)
            .HasDatabaseName("IX_AuditLog_Channel_Status_Occurred");

        builder.HasIndex(e => new { e.Target, e.OccurredAtUtc })
            .IsDescending(false, true)
            .HasFilter("[Target] IS NOT NULL")
            .HasDatabaseName("IX_AuditLog_Target_Occurred");
    }
}
