using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Tiku.Domain.Catalog;
using Tiku.Domain.Commerce;
using Tiku.Domain.Identity;

namespace Tiku.Infrastructure.Persistence.Configurations;

internal sealed class PointActivityTaskConfiguration : IEntityTypeConfiguration<PointActivityTask>
{
    public void Configure(EntityTypeBuilder<PointActivityTask> builder)
    {
        builder.ConfigureTenantEntity("point_activity_tasks");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.TaskKey).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Title).HasMaxLength(200);
        builder.Property(entity => entity.Description).HasMaxLength(1000);
        builder.Property(entity => entity.TaskType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.Rules).IsJson("{}");
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.TaskKey }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.Status, entity.SortOrder });
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_point_activity_tasks_points", "points > 0");
            table.HasCheckConstraint("ck_point_activity_tasks_max_claims", "max_claims_per_user > 0");
        });
    }
}

internal sealed class PointActivityClaimConfiguration : IEntityTypeConfiguration<PointActivityClaim>
{
    public void Configure(EntityTypeBuilder<PointActivityClaim> builder)
    {
        builder.ConfigureTenantEntity("point_activity_claims");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.TaskKey).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.SourceType).HasMaxLength(100);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.Property(entity => entity.ClaimedAt).HasDefaultValueSql("now()");
        builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.TaskId, entity.SourceType, entity.SourceId })
            .IsUnique()
            .HasFilter("source_type is not null and source_id is not null");
        builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.CreatedAt });
        builder.HasOne<PointActivityTask>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.TaskId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.Restrict);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_point_activity_claims_points", "points > 0");
        });
    }
}

internal sealed class PointExchangeItemConfiguration : IEntityTypeConfiguration<PointExchangeItem>
{
    public void Configure(EntityTypeBuilder<PointExchangeItem> builder)
    {
        builder.ConfigureTenantEntity("point_exchange_items");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.ItemKey).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Name).HasMaxLength(200);
        builder.Property(entity => entity.Description).HasMaxLength(1000);
        builder.Property(entity => entity.ItemType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.FulfillmentPayload).IsJson("{}");
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.ItemKey }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.RegionId, entity.Status, entity.SortOrder });
        builder.HasOne<Region>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.RegionId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_point_exchange_items_points_cost", "points_cost > 0");
            table.HasCheckConstraint("ck_point_exchange_items_stock", "stock is null or stock >= 0");
            table.HasCheckConstraint("ck_point_exchange_items_days", "days is null or days >= 0");
        });
    }
}

internal sealed class PointExchangeOrderConfiguration : IEntityTypeConfiguration<PointExchangeOrder>
{
    public void Configure(EntityTypeBuilder<PointExchangeOrder> builder)
    {
        builder.ConfigureTenantEntity("point_exchange_orders");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.OrderNo).HasMaxLength(100);
        builder.Property(entity => entity.ItemName).HasMaxLength(200);
        builder.Property(entity => entity.ItemType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.FulfillmentSnapshot).IsJson("{}");
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.Property(entity => entity.OrderedAt).HasDefaultValueSql("now()");
        builder.HasIndex(entity => new { entity.TenantId, entity.OrderNo }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.CreatedAt });
        builder.HasOne<PointExchangeItem>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.ItemId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.Restrict);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_point_exchange_orders_points_cost", "points_cost > 0");
        });
    }
}
