using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;

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

/// <summary>
/// Maps the <see cref="KpiRollupHourly"/> POCO to the central
/// <c>KpiRollupHourly</c> table — the hourly pre-aggregated row folded from raw
/// <c>KpiSample</c> rows by the recorder singleton. Operational history, NOT
/// audit, so the table is non-partitioned, standard <c>[PRIMARY]</c> filegroup,
/// no DB-role restriction (mirrors <see cref="KpiSampleEntityTypeConfiguration"/>).
/// </summary>
/// <remarks>
/// Two named indexes back the access paths: the UNIQUE <c>IX_KpiRollupHourly_Series</c>
/// on (Source/Metric/Scope/ScopeKey/HourStartUtc) is both the idempotent upsert key
/// and the covering index for the bucketed range read, while
/// <c>IX_KpiRollupHourly_Hour</c> backs the retention purge (delete by
/// <see cref="KpiRollupHourly.HourStartUtc"/>).
/// </remarks>
public class KpiRollupHourlyEntityTypeConfiguration : IEntityTypeConfiguration<KpiRollupHourly>
{
    /// <summary>
    /// Configures the EF Core entity type mapping for <see cref="KpiRollupHourly"/>.
    /// </summary>
    /// <param name="builder">The entity type builder to configure.</param>
    public void Configure(EntityTypeBuilder<KpiRollupHourly> builder)
    {
        builder.ToTable("KpiRollupHourly");

        // Surrogate long identity assigned by the store.
        builder.HasKey(r => r.Id);

        // Catalog-bounded ASCII columns — same series key and varchar sizes as
        // KpiSample (values come from the KpiSources / KpiScopes catalogs and
        // per-source metric names).
        builder.Property(r => r.Source).HasMaxLength(64).IsUnicode(false).IsRequired();
        builder.Property(r => r.Metric).HasMaxLength(64).IsUnicode(false).IsRequired();
        builder.Property(r => r.Scope).HasMaxLength(16).IsUnicode(false).IsRequired();

        // Scope qualifier — null for the Global scope.
        builder.Property(r => r.ScopeKey).HasMaxLength(64).IsUnicode(false);

        // Hour-truncated UTC bucket start.
        builder.Property(r => r.HourStartUtc).IsRequired();

        // Folded aggregate + fidelity columns — double / float and int.
        builder.Property(r => r.Value);
        builder.Property(r => r.MinValue);
        builder.Property(r => r.MaxValue);
        builder.Property(r => r.SampleCount);

        // Series index — UNIQUE, the idempotent upsert key AND the covering index
        // for the bucketed range read (filter one series, scan in hour order).
        // Names locked for migration discoverability. Global-scope rows
        // (ScopeKey IS NULL) are included and seeked via the IS NULL predicate.
        builder.HasIndex(r => new { r.Source, r.Metric, r.Scope, r.ScopeKey, r.HourStartUtc })
            .HasDatabaseName("IX_KpiRollupHourly_Series")
            .IsUnique()
            // Suppress EF's default "[ScopeKey] IS NOT NULL" filtered-index — Global-scope
            // rows (ScopeKey NULL) MUST participate in the uniqueness constraint so the
            // idempotent per-(series, hour) upsert holds for global rollups too.
            .HasFilter(null);

        // Hour index — backs the retention purge (delete by hour bucket).
        builder.HasIndex(r => r.HourStartUtc)
            .HasDatabaseName("IX_KpiRollupHourly_Hour");
    }
}
