using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ChatService.Domain.AggregatesModel.UserAggregate;

namespace ChatService.Infrastructure.EntityConfigurations;

/// <summary>
/// EN: Entity configuration for ChatUser aggregate root.
/// VI: Cấu hình entity cho ChatUser aggregate root.
/// </summary>
public class ChatUserEntityTypeConfiguration : IEntityTypeConfiguration<ChatUser>
{
    public void Configure(EntityTypeBuilder<ChatUser> builder)
    {
        builder.ToTable("chat_users");

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

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

        builder.Property(u => u.IdentityUserId)
            .HasColumnName("identity_user_id")
            .HasMaxLength(256)
            .IsRequired();

        builder.HasIndex(u => u.IdentityUserId)
            .IsUnique();

        builder.Property(u => u.DisplayName)
            .HasColumnName("display_name")
            .HasMaxLength(256)
            .IsRequired();

        builder.Property(u => u.AvatarUrl)
            .HasColumnName("avatar_url")
            .HasMaxLength(2048);

        builder.Property(u => u.CreatedAt)
            .HasColumnName("created_at")
            .IsRequired();

        builder.Property(u => u.UpdatedAt)
            .HasColumnName("updated_at")
            .IsRequired();

        builder.Property(u => u.LastSeenAt)
            .HasColumnName("last_seen_at");

        // EN: Configure Status as navigation to Enumeration
        // VI: Cấu hình Status như navigation đến Enumeration
        builder.Property<int>("_statusId")
            .UsePropertyAccessMode(PropertyAccessMode.Field)
            .HasColumnName("status_id")
            .IsRequired();

        builder.HasOne(u => u.Status)
            .WithMany()
            .HasForeignKey("_statusId");

        // EN: Configure KeyBundle as owned entity
        // VI: Cấu hình KeyBundle như owned entity
        builder.OwnsOne(u => u.KeyBundle, kb =>
        {
            kb.Property(k => k.IdentityPublicKey)
                .HasColumnName("identity_public_key")
                .HasMaxLength(1024);

            kb.Property(k => k.SignedPreKey)
                .HasColumnName("signed_pre_key")
                .HasMaxLength(1024);

            kb.Property(k => k.SignedPreKeySignature)
                .HasColumnName("signed_pre_key_signature")
                .HasMaxLength(1024);

            kb.Property(k => k.SignedPreKeyTimestamp)
                .HasColumnName("signed_pre_key_timestamp");
        });

        // EN: Configure OneTimePreKeys collection
        // VI: Cấu hình collection OneTimePreKeys
        var navigation = builder.Metadata.FindNavigation(nameof(ChatUser.OneTimePreKeys));
        navigation?.SetPropertyAccessMode(PropertyAccessMode.Field);

        builder.HasMany(u => u.OneTimePreKeys)
            .WithOne()
            .HasForeignKey(k => k.UserId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

/// <summary>
/// EN: Entity configuration for OneTimePreKey entity.
/// VI: Cấu hình entity cho OneTimePreKey entity.
/// </summary>
public class OneTimePreKeyEntityTypeConfiguration : IEntityTypeConfiguration<OneTimePreKey>
{
    public void Configure(EntityTypeBuilder<OneTimePreKey> builder)
    {
        builder.ToTable("one_time_pre_keys");

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

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

        builder.Property(k => k.UserId)
            .HasColumnName("user_id")
            .IsRequired();

        builder.Property(k => k.KeyId)
            .HasColumnName("key_id")
            .IsRequired();

        builder.Property(k => k.PublicKey)
            .HasColumnName("public_key")
            .HasMaxLength(1024)
            .IsRequired();

        builder.Property(k => k.IsUsed)
            .HasColumnName("is_used")
            .IsRequired();

        builder.Property(k => k.CreatedAt)
            .HasColumnName("created_at")
            .IsRequired();

        builder.Property(k => k.UsedAt)
            .HasColumnName("used_at");

        // EN: Index for finding available keys
        // VI: Index để tìm các keys còn khả dụng
        builder.HasIndex(k => new { k.UserId, k.IsUsed });
    }
}

/// <summary>
/// EN: Entity configuration for UserStatus enumeration.
/// VI: Cấu hình entity cho UserStatus enumeration.
/// </summary>
public class UserStatusEntityTypeConfiguration : IEntityTypeConfiguration<UserStatus>
{
    public void Configure(EntityTypeBuilder<UserStatus> builder)
    {
        builder.ToTable("user_statuses");

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

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

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

        // EN: Seed data
        // VI: Dữ liệu seed
        builder.HasData(
            UserStatus.Offline,
            UserStatus.Online,
            UserStatus.Away,
            UserStatus.DoNotDisturb
        );
    }
}
