using Baya.Domain.Entities.Booking;
using Baya.Infrastructure.Persistence.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Baya.Infrastructure.Persistence.Configuration.BookingConfig;

internal sealed class CancellationPolicyConfig : IEntityTypeConfiguration<CancellationPolicy>
{
    public void Configure(EntityTypeBuilder<CancellationPolicy> builder)
    {
        builder.ToTable("CancellationPolicies", "booking");

        builder.Property(p => p.Code).HasMaxLength(50).IsRequired();
        builder.Property(p => p.AppliesTo).HasMaxLength(20).IsRequired();
        builder.Property(p => p.RefundPercentage).HasPrecision(5, 2);
        builder.Property(p => p.FeeRate).HasPrecision(5, 4);

        builder.HasIndex(p => p.Code).IsUnique();
        builder.HasIndex(p => new { p.AppliesTo, p.IsActive });

        builder.HasQueryFilter(p => p.DeletedAt == null);

        builder.HasData(Seed());
    }

    // Baseline tiers, seeded via HasData so they land with this phase's migration on a fresh DB. Numbers the
    // product doc leaves open (the nurse penalty) default safe and are flagged in the phase report — the
    // nurse-no-show penalty is modelled (FeeRate) but posting it is deferred to payouts (b13).
    private static object[] Seed()
    {
        var ts = SeedConstants.Timestamp;

        (long Id, string Code, string AppliesTo, int? Min, int? Max, decimal Refund, long Fee, decimal? Rate)[] rows =
        [
            (1, CancellationPolicyCode.Standard24h, CancellationActor.Customer, 24, null, 100m, 0L, null),
            // Open lower bound so a cancel < 24h before start (or after it) always resolves a customer tier.
            (2, CancellationPolicyCode.StandardInside24h, CancellationActor.Customer, null, 24, 50m, 0L, null),
            (3, CancellationPolicyCode.NurseNoShow, CancellationActor.Nurse, null, null, 100m, 0L, 0m),
            (4, CancellationPolicyCode.AdminCancellation, CancellationActor.Admin, null, null, 100m, 0L, null),
        ];

        return rows
            .Select(r => (object)new
            {
                r.Id,
                r.Code,
                r.AppliesTo,
                HoursBeforeStartMin = r.Min,
                HoursBeforeStartMax = r.Max,
                RefundPercentage = r.Refund,
                FeeAmountIrr = r.Fee,
                FeeRate = r.Rate,
                IsActive = true,
                CreatedAt = ts
            })
            .ToArray();
    }
}
