using Baya.Domain.Entities.Booking;
using Baya.Domain.Entities.Catalog;
using Baya.Domain.Entities.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Baya.Infrastructure.Persistence.Configuration.BookingConfig;

internal sealed class BookingConfig : IEntityTypeConfiguration<Booking>
{
    public void Configure(EntityTypeBuilder<Booking> builder)
    {
        // The three-amount split is a DB CHECK (not handler-only): gross = commission + payout, all ≥ 0.
        builder.ToTable("Bookings", "booking", t => t.HasCheckConstraint(
            "CK_Bookings_AmountSplit",
            "[GrossPriceIrr] = [BalinyaarCommissionIrr] + [NursePayoutAmount] " +
            "AND [GrossPriceIrr] >= 0 AND [BalinyaarCommissionIrr] >= 0 AND [NursePayoutAmount] >= 0"));

        // Snapshots freeze history. AddressSnapshotJson is encrypted at rest (converter wired in
        // ApplicationDbContext); both are nvarchar(max) so no length cap.
        builder.Property(b => b.VariantSnapshotJson).IsRequired();
        builder.Property(b => b.AddressSnapshotJson).IsRequired();

        builder.Property(b => b.PlatformFeeRate).HasPrecision(5, 4);
        builder.Property(b => b.CancellationRefundPercentage).HasPrecision(5, 2);

        builder.Property(b => b.Status).HasMaxLength(30).IsRequired();
        builder.Property(b => b.CancellationReason).HasMaxLength(500);
        builder.Property(b => b.CancelledBy).HasMaxLength(20);
        builder.Property(b => b.CancellationPolicyCode).HasMaxLength(50);

        builder.HasIndex(b => new { b.CustomerId, b.Status });
        builder.HasIndex(b => new { b.NurseId, b.Status });
        // b13 selects payout-eligible bookings through the dispute-window close.
        builder.HasIndex(b => b.DisputeWindowEndsAt);

        // 1:1 with the request that created it (UNIQUE index created automatically). No navigation either
        // side — the request is read by id at conversion time.
        builder.HasOne<BookingRequest>()
            .WithOne()
            .HasForeignKey<Booking>(b => b.BookingRequestId)
            .IsRequired();

        // Denormalized FKs for query performance (no navigations on Booking). partner_center_id is left
        // FK-less and nullable — partner_centers is DEFERRED to b15.
        builder.HasOne<CustomerProfile>().WithMany().HasForeignKey(b => b.CustomerId).IsRequired();
        builder.HasOne<NurseProfile>().WithMany().HasForeignKey(b => b.NurseId).IsRequired();
        builder.HasOne<Patient>().WithMany().HasForeignKey(b => b.PatientId).IsRequired();
        builder.HasOne<NurseServiceVariant>().WithMany().HasForeignKey(b => b.VariantId).IsRequired();
        builder.HasOne<CustomerAddress>().WithMany().HasForeignKey(b => b.CustomerAddressId).IsRequired();

        builder.HasMany(b => b.Sessions).WithOne(s => s.Booking).HasForeignKey(s => s.BookingId);

        builder.HasQueryFilter(b => b.DeletedAt == null);
    }
}
