using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;

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

public class InstanceConfiguration : IEntityTypeConfiguration<Instance>
{
    /// <summary>Configures the EF Core mapping for <see cref="Instance"/>.</summary>
    /// <param name="builder">The entity type builder.</param>
    public void Configure(EntityTypeBuilder<Instance> builder)
    {
        builder.HasKey(i => i.Id);

        builder.Property(i => i.UniqueName)
            .IsRequired()
            .HasMaxLength(200);

        builder.Property(i => i.State)
            .HasConversion<string>()
            .HasMaxLength(50);

        builder.HasOne<Template>()
            .WithMany()
            .HasForeignKey(i => i.TemplateId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne<Site>()
            .WithMany()
            .HasForeignKey(i => i.SiteId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne<Area>()
            .WithMany()
            .HasForeignKey(i => i.AreaId)
            .OnDelete(DeleteBehavior.SetNull)
            .IsRequired(false);

        builder.HasMany(i => i.AttributeOverrides)
            .WithOne()
            .HasForeignKey(o => o.InstanceId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasMany(i => i.AlarmOverrides)
            .WithOne()
            .HasForeignKey(o => o.InstanceId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasMany(i => i.ConnectionBindings)
            .WithOne()
            .HasForeignKey(b => b.InstanceId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasMany(i => i.NativeAlarmSourceOverrides)
            .WithOne()
            .HasForeignKey(o => o.InstanceId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasIndex(i => new { i.SiteId, i.UniqueName }).IsUnique();
    }
}

public class InstanceNativeAlarmSourceOverrideConfiguration : IEntityTypeConfiguration<InstanceNativeAlarmSourceOverride>
{
    /// <summary>Configures the EF Core mapping for <see cref="InstanceNativeAlarmSourceOverride"/>.</summary>
    /// <param name="builder">The entity type builder.</param>
    public void Configure(EntityTypeBuilder<InstanceNativeAlarmSourceOverride> builder)
    {
        builder.HasKey(o => o.Id);

        builder.Property(o => o.SourceCanonicalName)
            .IsRequired()
            .HasMaxLength(400); // Larger than names to fit composed paths.

        builder.Property(o => o.ConnectionNameOverride)
            .HasMaxLength(200);

        builder.Property(o => o.SourceReferenceOverride)
            .HasMaxLength(1000);

        builder.Property(o => o.ConditionFilterOverride)
            .HasMaxLength(1000);

        builder.HasIndex(o => new { o.InstanceId, o.SourceCanonicalName }).IsUnique();
    }
}

public class InstanceAttributeOverrideConfiguration : IEntityTypeConfiguration<InstanceAttributeOverride>
{
    /// <summary>Configures the EF Core mapping for <see cref="InstanceAttributeOverride"/>.</summary>
    /// <param name="builder">The entity type builder.</param>
    public void Configure(EntityTypeBuilder<InstanceAttributeOverride> builder)
    {
        builder.HasKey(o => o.Id);

        builder.Property(o => o.AttributeName)
            .IsRequired()
            .HasMaxLength(200);

        // nvarchar(max): List attribute values (JSON arrays) can exceed 4000 chars.
        builder.Property(o => o.OverrideValue);

        builder.Property(o => o.ElementDataType)
            .HasConversion<string>()
            .HasMaxLength(50);

        builder.HasIndex(o => new { o.InstanceId, o.AttributeName }).IsUnique();
    }
}

public class InstanceAlarmOverrideConfiguration : IEntityTypeConfiguration<InstanceAlarmOverride>
{
    /// <summary>Configures the EF Core mapping for <see cref="InstanceAlarmOverride"/>.</summary>
    /// <param name="builder">The entity type builder.</param>
    public void Configure(EntityTypeBuilder<InstanceAlarmOverride> builder)
    {
        builder.HasKey(o => o.Id);

        builder.Property(o => o.AlarmCanonicalName)
            .IsRequired()
            .HasMaxLength(400); // Larger than attribute names to fit composed paths.

        builder.Property(o => o.TriggerConfigurationOverride)
            .HasMaxLength(4000);

        builder.HasIndex(o => new { o.InstanceId, o.AlarmCanonicalName }).IsUnique();
    }
}

public class InstanceConnectionBindingConfiguration : IEntityTypeConfiguration<InstanceConnectionBinding>
{
    /// <summary>Configures the EF Core mapping for <see cref="InstanceConnectionBinding"/>.</summary>
    /// <param name="builder">The entity type builder.</param>
    public void Configure(EntityTypeBuilder<InstanceConnectionBinding> builder)
    {
        builder.HasKey(b => b.Id);

        builder.Property(b => b.AttributeName)
            .IsRequired()
            .HasMaxLength(200);

        builder.Property(b => b.DataSourceReferenceOverride)
            .HasMaxLength(512)
            .IsRequired(false);

        builder.HasOne<DataConnection>()
            .WithMany()
            .HasForeignKey(b => b.DataConnectionId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasIndex(b => new { b.InstanceId, b.AttributeName }).IsUnique();
    }
}

public class AreaConfiguration : IEntityTypeConfiguration<Area>
{
    /// <summary>Configures the EF Core mapping for <see cref="Area"/>.</summary>
    /// <param name="builder">The entity type builder.</param>
    public void Configure(EntityTypeBuilder<Area> builder)
    {
        builder.HasKey(a => a.Id);

        builder.Property(a => a.Name)
            .IsRequired()
            .HasMaxLength(200);

        builder.HasOne<Site>()
            .WithMany()
            .HasForeignKey(a => a.SiteId)
            .OnDelete(DeleteBehavior.Cascade);

        // Self-referencing parent area
        builder.HasOne<Area>()
            .WithMany(a => a.Children)
            .HasForeignKey(a => a.ParentAreaId)
            .OnDelete(DeleteBehavior.Restrict)
            .IsRequired(false);

        builder.HasIndex(a => new { a.SiteId, a.ParentAreaId, a.Name }).IsUnique();
    }
}
