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

namespace Baya.Infrastructure.Persistence.Configuration.PaymentsConfig;

internal sealed class PaymentTransactionConfig : IEntityTypeConfiguration<PaymentTransaction>
{
    public void Configure(EntityTypeBuilder<PaymentTransaction> builder)
    {
        builder.ToTable("PaymentTransactions", "payments");

        builder.Property(t => t.Currency).HasMaxLength(3).IsRequired();
        builder.Property(t => t.Status).HasMaxLength(20).IsRequired();
        builder.Property(t => t.GatewayTransactionId).HasMaxLength(200);
        builder.Property(t => t.GatewayReferenceCode).HasMaxLength(200);
        builder.Property(t => t.GatewayResponseCode).HasMaxLength(50);
        builder.Property(t => t.IpAddress).HasMaxLength(64);
        builder.Property(t => t.UserAgent).HasMaxLength(400);

        // The two structural idempotency guards (the whole point of the phase). SQL Server/SQLite both honour
        // filtered (partial) unique indexes; NULLs sit outside the filter so pending rows don't collide.
        builder.HasIndex(t => t.GatewayReferenceCode)
            .IsUnique()
            .HasFilter("[GatewayReferenceCode] IS NOT NULL");

        // At most one capturing transaction per booking — the authoritative anti-double-capture backstop.
        builder.HasIndex(t => t.BookingId)
            .IsUnique()
            .HasFilter("[Status] = 'succeeded' AND [BookingId] IS NOT NULL");

        // The lookup used by initiate/confirm (attempts for a request/booking by status).
        builder.HasIndex(t => new { t.BookingId, t.Status });
        builder.HasIndex(t => new { t.BookingRequestId, t.Status });

        builder.HasOne<BookingRequest>().WithMany().HasForeignKey(t => t.BookingRequestId).IsRequired();
        builder.HasOne<Booking>().WithMany().HasForeignKey(t => t.BookingId).IsRequired(false);
        builder.HasOne<CustomerProfile>().WithMany().HasForeignKey(t => t.CustomerId).IsRequired();
        builder.HasOne<PaymentGateway>().WithMany().HasForeignKey(t => t.GatewayId).IsRequired();

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