#nullable enable
using System.Globalization;
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Configuration;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Booking;
using Baya.Application.Models.Common;
using Baya.Domain.Entities.Booking;
using Baya.Domain.Entities.User;
using Mediator;

namespace Baya.Application.Features.Booking.Queries.GetCheckoutSummary;

internal sealed class GetCheckoutSummaryQueryHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IPlatformConfig platformConfig)
    : IRequestHandler<GetCheckoutSummaryQuery, OperationResult<CheckoutSummaryDto>>
{
    public async ValueTask<OperationResult<CheckoutSummaryDto>> Handle(GetCheckoutSummaryQuery request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<CheckoutSummaryDto>.UnauthorizedResult("Not authenticated.");

        if (currentUser.Roles?.Contains(RoleNames.Customer) != true)
            return OperationResult<CheckoutSummaryDto>.ForbiddenResult("Only a customer can read a checkout summary.");

        var customerId = await unitOfWork.CustomerProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (customerId is not { } cid)
            return OperationResult<CheckoutSummaryDto>.NotFoundResult("Booking request not found.");

        var ctx = await unitOfWork.BookingRequestRepository.GetCheckoutContextAsync(request.BookingRequestId, cid, cancellationToken);
        if (ctx is null)
            return OperationResult<CheckoutSummaryDto>.NotFoundResult("Booking request not found.");

        var sessions = ctx.SessionCount is > 0 ? ctx.SessionCount.Value : 1;
        var gross = ctx.VariantPrice * sessions;

        var feeRate = await platformConfig.GetConfig<decimal>("platform_fee_rate", cancellationToken);
        var vatRate = await platformConfig.GetConfig<decimal>("vat_rate", cancellationToken);

        // b10 split (VAT-inclusive commission), then carve VAT out of the commission so the display
        // decomposition reconciles to the captured total: serviceCost + commissionNet + vat = gross.
        var (commission, payout) = BookingAmounts.Split(gross, feeRate);
        var commissionNet = (long)decimal.Round(commission / (1 + vatRate), MidpointRounding.AwayFromZero);
        var vat = commission - commissionNet;

        var dto = new CheckoutSummaryDto(
            ctx.Id,
            ctx.Status,
            ctx.NurseName,
            ctx.PatientName,
            ctx.VariantLabel,
            ctx.VariantPriceUnit,
            ctx.SessionCount,
            ctx.RequestedDate,
            ctx.RequestedTimeStart,
            ctx.RequestedTimeEnd,
            ctx.PaymentDeadlineAt,
            Str(payout),
            Str(commissionNet),
            Str(vat),
            vatRate,
            Str(gross),
            Str(gross),
            Str(commission),
            Str(payout));

        return OperationResult<CheckoutSummaryDto>.SuccessResult(dto);
    }

    private static string Str(long value) => value.ToString(CultureInfo.InvariantCulture);
}
