// EN: Entity configuration for Shop aggregate.
// VI: Cấu hình entity cho Shop aggregate.

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MerchantService.Domain.AggregatesModel.ShopAggregate;

namespace MerchantService.Infrastructure.EntityConfigurations;

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

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

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

        builder.Property<Guid>("_merchantId")
            .HasColumnName("merchant_id")
            .IsRequired();

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

        builder.Property<string>("_slug")
            .HasColumnName("slug")
            .HasMaxLength(100)
            .IsRequired();

        builder.Property(s => s.TypeId)
            .HasColumnName("type_id")
            .IsRequired();

        builder.Property(s => s.CategoryId)
            .HasColumnName("category_id")
            .IsRequired();

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

        builder.Property<string?>("_description")
            .HasColumnName("description")
            .HasMaxLength(2000);

        builder.Property<string?>("_logoUrl")
            .HasColumnName("logo_url")
            .HasMaxLength(500);

        builder.Property<string?>("_coverImageUrl")
            .HasColumnName("cover_image_url")
            .HasMaxLength(500);

        // EN: Configure owned entity for ContactInfo
        // VI: Cấu hình owned entity cho ContactInfo
        builder.OwnsOne<ContactInfo>("_contactInfo", ci =>
        {
            ci.Property(c => c.Phone)
                .HasColumnName("phone")
                .HasMaxLength(20);

            ci.Property(c => c.Email)
                .HasColumnName("email")
                .HasMaxLength(100);

            ci.Property(c => c.Website)
                .HasColumnName("website")
                .HasMaxLength(200);
        });

        // EN: Configure owned entity for OperatingHours
        // VI: Cấu hình owned entity cho OperatingHours
        builder.OwnsOne<OperatingHours>("_operatingHours", oh =>
        {
            oh.Property(o => o.OpenTime)
                .HasColumnName("open_time");

            oh.Property(o => o.CloseTime)
                .HasColumnName("close_time");

            oh.Property(o => o.OpenDays)
                .HasColumnName("open_days")
                .HasConversion(
                    v => string.Join(",", v.Select(d => (int)d)),
                    v => v.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(s => (DayOfWeek)int.Parse(s)).ToList()
                );
        });

        // EN: Configure owned entity for ShopFeatures (JSONB for Multi-vertical)
        // VI: Cấu hình owned entity cho ShopFeatures (JSONB cho Đa ngành hàng)
        builder.OwnsOne<ShopFeatures>("_features", sf =>
        {
            sf.ToJson("features_config");
        });

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

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

        builder.Property<bool>("_isDefault")
            .HasColumnName("is_default")
            .HasDefaultValue(false);

        builder.Property<bool>("_isDeleted")
            .HasColumnName("is_deleted")
            .HasDefaultValue(false);

        // EN: Configure navigation to branches
        // VI: Cấu hình navigation đến branches
        builder.HasMany(s => s.Branches)
            .WithOne()
            .HasForeignKey(b => b.ShopId)
            .OnDelete(DeleteBehavior.Cascade);

        // EN: Indexes
        // VI: Indexes
        builder.HasIndex("_merchantId").HasDatabaseName("ix_shops_merchant_id");
        builder.HasIndex("_slug").IsUnique().HasDatabaseName("ix_shops_slug");
        builder.HasIndex(s => s.StatusId).HasDatabaseName("ix_shops_status");
        builder.HasIndex(s => s.CategoryId).HasDatabaseName("ix_shops_category");

        // EN: Ignore expression-bodied properties (EF Core can't map them)
        // EN: Repository queries use EF.Property<T>() to access backing fields directly.
        // VI: Ignore expression-bodied properties (EF Core không thể map chúng)
        builder.Ignore(s => s.Type);
        builder.Ignore(s => s.Category);
        builder.Ignore(s => s.Status);
        builder.Ignore(s => s.ContactInfo);
        builder.Ignore(s => s.OperatingHours);
        builder.Ignore(s => s.Features);
        builder.Ignore(s => s.Name);
        builder.Ignore(s => s.Slug);
        builder.Ignore(s => s.Description);
        builder.Ignore(s => s.LogoUrl);
        builder.Ignore(s => s.CoverImageUrl);
        builder.Ignore(s => s.MerchantId);
        builder.Ignore(s => s.CreatedAt);
        builder.Ignore(s => s.UpdatedAt);
        builder.Ignore(s => s.IsDefault);
        builder.Ignore(s => s.IsDeleted);
    }
}

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

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

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

        builder.Property(b => b.ShopId)
            .HasColumnName("shop_id")
            .IsRequired();

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

        builder.Property<string?>("_code")
            .HasColumnName("code")
            .HasMaxLength(20);

        builder.Property<string?>("_phone")
            .HasColumnName("phone")
            .HasMaxLength(20);

        builder.Property<bool>("_isActive")
            .HasColumnName("is_active")
            .HasDefaultValue(true);

        // EN: Configure owned entity for Address
        // VI: Cấu hình owned entity cho Address
        builder.OwnsOne<Address>("_address", a =>
        {
            a.Property(x => x.Street)
                .HasColumnName("street")
                .HasMaxLength(200)
                .IsRequired();

            a.Property(x => x.Ward)
                .HasColumnName("ward")
                .HasMaxLength(100);

            a.Property(x => x.District)
                .HasColumnName("district")
                .HasMaxLength(100)
                .IsRequired();

            a.Property(x => x.City)
                .HasColumnName("city")
                .HasMaxLength(100)
                .IsRequired();

            a.Property(x => x.Province)
                .HasColumnName("province")
                .HasMaxLength(100);

            a.Property(x => x.PostalCode)
                .HasColumnName("postal_code")
                .HasMaxLength(20);

            a.Property(x => x.CountryCode)
                .HasColumnName("country_code")
                .HasMaxLength(2)
                .HasDefaultValue("VN");
        });

        // EN: Configure owned entity for GeoLocation
        // VI: Cấu hình owned entity cho GeoLocation
        builder.OwnsOne<GeoLocation>("_location", l =>
        {
            l.Property(x => x.Latitude)
                .HasColumnName("latitude");

            l.Property(x => x.Longitude)
                .HasColumnName("longitude");
        });

        // EN: Configure owned entity for OperatingHours
        // VI: Cấu hình owned entity cho OperatingHours
        builder.OwnsOne<OperatingHours>("_operatingHours", oh =>
        {
            oh.Property(o => o.OpenTime)
                .HasColumnName("open_time");

            oh.Property(o => o.CloseTime)
                .HasColumnName("close_time");

            oh.Property(o => o.OpenDays)
                .HasColumnName("open_days")
                .HasConversion(
                    v => string.Join(",", v.Select(d => (int)d)),
                    v => v.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(s => (DayOfWeek)int.Parse(s)).ToList()
                );
        });

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

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

        // EN: Indexes
        // VI: Indexes
        builder.HasIndex(b => b.ShopId).HasDatabaseName("ix_shop_branches_shop_id");

        // EN: Ignore expression-bodied properties (repository queries use EF.Property)
        // VI: Ignore expression-bodied properties (repository queries dùng EF.Property)
        builder.Ignore(b => b.Address);
        builder.Ignore(b => b.Location);
        builder.Ignore(b => b.OperatingHours);
        builder.Ignore(b => b.Name);
        builder.Ignore(b => b.Code);
        builder.Ignore(b => b.Phone);
        builder.Ignore(b => b.IsActive);
        builder.Ignore(b => b.CreatedAt);
        builder.Ignore(b => b.UpdatedAt);
    }
}

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

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

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

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

        builder.HasData(
            ShopType.OnlineOnly,
            ShopType.PhysicalOnly,
            ShopType.Hybrid
        );
    }
}

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

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

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

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

        builder.HasData(
            ShopStatus.Draft,
            ShopStatus.Active,
            ShopStatus.Inactive,
            ShopStatus.Closed
        );
    }
}

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

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

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

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

        builder.HasData(
            BusinessCategory.FoodBeverage,
            BusinessCategory.Fashion,
            BusinessCategory.Electronics,
            BusinessCategory.Healthcare,
            BusinessCategory.Beauty,
            BusinessCategory.Education,
            BusinessCategory.Entertainment,
            BusinessCategory.Services,
            BusinessCategory.Grocery,
            BusinessCategory.HomeFurniture,
            BusinessCategory.Other,
            // Vertical-specific categories
            BusinessCategory.Cafe,
            BusinessCategory.Restaurant,
            BusinessCategory.Karaoke,
            BusinessCategory.Spa
        );
    }
}
