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

namespace MktXService.Infrastructure.EntityConfigurations;

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

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

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

        builder.Property<Guid>("_contactId")
            .HasColumnName("contact_id")
            .IsRequired();

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

        builder.Property(c => c.StatusId)
            .HasColumnName("status_id")
            .IsRequired();

        builder.Property<string>("_channel")
            .HasColumnName("channel")
            .HasMaxLength(50)
            .IsRequired();

        builder.Property<Guid?>("_assignedToUserId")
            .HasColumnName("assigned_to_user_id");

        builder.Property<DateTime>("_startedAt")
            .HasColumnName("started_at")
            .IsRequired();

        builder.Property<DateTime?>("_closedAt")
            .HasColumnName("closed_at");

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

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

        // EN: Relationships
        builder.HasOne(c => c.Status)
            .WithMany()
            .HasForeignKey(c => c.StatusId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasMany(c => c.Messages)
            .WithOne()
            .HasForeignKey(m => m.ConversationId)
            .OnDelete(DeleteBehavior.Cascade);

        // EN: Indexes
        builder.HasIndex("_contactId")
            .HasDatabaseName("ix_conversations_contact_id");

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

        builder.HasIndex(c => c.StatusId)
            .HasDatabaseName("ix_conversations_status_id");

        builder.HasIndex("_assignedToUserId")
            .HasDatabaseName("ix_conversations_assigned_user");

        // EN: Composite for finding open conversations per contact
        builder.HasIndex("_contactId", "StatusId")
            .HasDatabaseName("ix_conversations_contact_status");
    }
}

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

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

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

        builder.Property(s => s.Name)
            .HasColumnName("name")
            .HasMaxLength(50)
            .IsRequired();

        builder.HasData(
            ConversationStatus.Open,
            ConversationStatus.Closed,
            ConversationStatus.Pending
        );
    }
}

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

    public void Configure(EntityTypeBuilder<Message> builder)
    {
        builder.ToTable("messages");

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

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

        builder.Property(m => m.ConversationId)
            .HasColumnName("conversation_id")
            .IsRequired();

        builder.Property<string?>("_twitterMessageId")
            .HasColumnName("twitter_message_id")
            .HasMaxLength(100);

        builder.Property<string>("_direction")
            .HasColumnName("direction")
            .HasMaxLength(20)
            .IsRequired();

        builder.Property<string>("_type")
            .HasColumnName("type")
            .HasMaxLength(50)
            .IsRequired();

        builder.Property<string>("_content")
            .HasColumnName("content")
            .IsRequired();

        // EN: Attachments as JSONB
        builder.Property<List<MessageAttachment>?>("_attachments")
            .HasColumnName("attachments")
            .HasColumnType("jsonb")
            .HasConversion(
                v => v == null ? null : JsonSerializer.Serialize(v, JsonOptions),
                v => v == null ? null : JsonSerializer.Deserialize<List<MessageAttachment>>(v, JsonOptions));

        builder.Property<bool>("_isFromBot")
            .HasColumnName("is_from_bot")
            .IsRequired();

        builder.Property<DateTime>("_sentAt")
            .HasColumnName("sent_at")
            .IsRequired();

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

        // EN: Indexes
        builder.HasIndex(m => m.ConversationId)
            .HasDatabaseName("ix_messages_conversation_id");

        builder.HasIndex("_twitterMessageId")
            .HasDatabaseName("ix_messages_twitter_id");

        builder.HasIndex("_sentAt")
            .HasDatabaseName("ix_messages_sent_at");
    }
}
