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

namespace MktXService.Infrastructure.EntityConfigurations;

/// <summary>
/// EN: EF Core configuration for TwitterAccount entity.
/// VI: Cấu hình EF Core cho entity TwitterAccount.
/// </summary>
/// <remarks>
/// <para>
/// EN: SECURITY NOTE: OAuth tokens (_oauthToken, _oauthTokenSecret) are stored as-is in this configuration.
/// In production, these should be encrypted using IDataProtector before storage.
/// Consider implementing a ValueConverter that uses DataProtectionProvider for encryption/decryption.
/// </para>
/// <para>
/// VI: LƯU Ý BẢO MẬT: OAuth tokens (_oauthToken, _oauthTokenSecret) được lưu nguyên trong cấu hình này.
/// Trong production, nên mã hóa bằng IDataProtector trước khi lưu.
/// Xem xét triển khai ValueConverter sử dụng DataProtectionProvider để mã hóa/giải mã.
/// </para>
/// </remarks>
public class TwitterAccountEntityTypeConfiguration : IEntityTypeConfiguration<TwitterAccount>
{
    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false
    };

    public void Configure(EntityTypeBuilder<TwitterAccount> builder)
    {
        builder.ToTable("twitter_accounts");

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

        builder.Ignore(a => a.DomainEvents);

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

        builder.Property<Guid>("_merchantId")
            .HasColumnName("merchant_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(a => a.StatusId)
            .HasColumnName("status_id")
            .IsRequired();

        // EN: OAuth tokens - SHOULD BE ENCRYPTED IN PRODUCTION
        // VI: OAuth tokens - NÊN ĐƯỢC MÃ HÓA TRONG PRODUCTION
        builder.Property<string>("_oauthToken")
            .HasColumnName("oauth_token")
            .IsRequired();

        builder.Property<string>("_oauthTokenSecret")
            .HasColumnName("oauth_token_secret")
            .IsRequired();

        builder.Property<string?>("_webhookId")
            .HasColumnName("webhook_id")
            .HasMaxLength(100);

        // EN: Settings as JSONB
        // VI: Settings dạng JSONB
        builder.Property<Dictionary<string, object>>("_settings")
            .HasColumnName("settings")
            .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>("_connectedAt")
            .HasColumnName("connected_at")
            .IsRequired();

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

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

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

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

        builder.HasIndex("_merchantId")
            .HasDatabaseName("ix_twitter_accounts_merchant_id");

        builder.HasIndex(a => a.StatusId)
            .HasDatabaseName("ix_twitter_accounts_status_id");
    }
}

/// <summary>
/// EN: EF Core configuration for TwitterAccountStatus enumeration.
/// VI: Cấu hình EF Core cho enumeration TwitterAccountStatus.
/// </summary>
public class TwitterAccountStatusEntityTypeConfiguration : IEntityTypeConfiguration<TwitterAccountStatus>
{
    public void Configure(EntityTypeBuilder<TwitterAccountStatus> builder)
    {
        builder.ToTable("twitter_account_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(
            TwitterAccountStatus.Pending,
            TwitterAccountStatus.Active,
            TwitterAccountStatus.Inactive,
            TwitterAccountStatus.Error,
            TwitterAccountStatus.Disconnected
        );
    }
}
