using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MktXService.Domain.AggregatesModel.ContactAggregate;

namespace MktXService.Infrastructure.EntityConfigurations;

/// <summary>
/// EN: EF Core configuration for Contact entity.
/// VI: Cấu hình EF Core cho entity Contact.
/// </summary>
public class ContactEntityTypeConfiguration : IEntityTypeConfiguration<Contact>
{
    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false
    };

    public void Configure(EntityTypeBuilder<Contact> builder)
    {
        builder.ToTable("contacts");

        builder.HasKey(c => c.Id);
        builder.Ignore(c => c.DomainEvents);

        builder.Property(c => c.Id)
            .HasColumnName("id")
            .IsRequired();

        builder.Property<Guid>("_accountId")
            .HasColumnName("account_id")
            .IsRequired();

        builder.Property<string>("_twitterUserId")
            .HasColumnName("twitter_user_id")
            .HasMaxLength(100)
            .IsRequired();

        builder.Property<string>("_username")
            .HasColumnName("username")
            .HasMaxLength(100)
            .IsRequired();

        builder.Property<string?>("_displayName")
            .HasColumnName("display_name")
            .HasMaxLength(200);

        builder.Property<string?>("_profileImageUrl")
            .HasColumnName("profile_image_url")
            .HasMaxLength(500);

        builder.Property<string>("_source")
            .HasColumnName("source")
            .HasMaxLength(50)
            .IsRequired();

        // EN: Custom attributes as JSONB
        // VI: Thuộc tính tùy chỉnh dạng JSONB
        builder.Property<Dictionary<string, object>>("_attributes")
            .HasColumnName("attributes")
            .HasColumnType("jsonb")
            .HasConversion(
                v => JsonSerializer.Serialize(v, JsonOptions),
                v => JsonSerializer.Deserialize<Dictionary<string, object>>(v, JsonOptions) 
                     ?? new Dictionary<string, object>(),
                new ValueComparer<Dictionary<string, object>>(
                    (c1, c2) => c1!.SequenceEqual(c2!),
                    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
                    c => new Dictionary<string, object>(c)));

        builder.Property<DateTime>("_firstInteractionAt")
            .HasColumnName("first_interaction_at")
            .IsRequired();

        builder.Property<DateTime?>("_lastInteractionAt")
            .HasColumnName("last_interaction_at");

        builder.Property<DateTime>("_createdAt")
            .HasColumnName("created_at")
            .IsRequired();

        builder.Property<DateTime?>("_updatedAt")
            .HasColumnName("updated_at");

        // EN: One-to-many with ContactTags
        // VI: Quan hệ một-nhiều với ContactTags
        builder.HasMany(c => c.Tags)
            .WithOne()
            .HasForeignKey(t => t.ContactId)
            .OnDelete(DeleteBehavior.Cascade);

        // EN: Unique constraint on account_id + twitter_user_id
        // VI: Ràng buộc unique trên account_id + twitter_user_id
        builder.HasIndex("_accountId", "_twitterUserId")
            .IsUnique()
            .HasDatabaseName("ix_contacts_account_twitter_user");

        builder.HasIndex("_accountId")
            .HasDatabaseName("ix_contacts_account_id");

        builder.HasIndex("_username")
            .HasDatabaseName("ix_contacts_username");

        builder.HasIndex("_lastInteractionAt")
            .HasDatabaseName("ix_contacts_last_interaction");
    }
}

/// <summary>
/// EN: EF Core configuration for ContactTag entity.
/// VI: Cấu hình EF Core cho entity ContactTag.
/// </summary>
public class ContactTagEntityTypeConfiguration : IEntityTypeConfiguration<ContactTag>
{
    public void Configure(EntityTypeBuilder<ContactTag> builder)
    {
        builder.ToTable("contact_tags");

        builder.HasKey(t => t.Id);

        builder.Property(t => t.Id)
            .HasColumnName("id")
            .IsRequired();

        builder.Property(t => t.ContactId)
            .HasColumnName("contact_id")
            .IsRequired();

        builder.Property<string>("_name")
            .HasColumnName("name")
            .HasMaxLength(100)
            .IsRequired();

        builder.Property<DateTime>("_createdAt")
            .HasColumnName("created_at")
            .IsRequired();

        // EN: Unique per contact
        builder.HasIndex(t => t.ContactId, "_name")
            .IsUnique()
            .HasDatabaseName("ix_contact_tags_contact_name");

        builder.HasIndex("_name")
            .HasDatabaseName("ix_contact_tags_name");
    }
}
