using MediatR;
using TakeoutSaaS.Application.App.Payments.Dto;
using TakeoutSaaS.Application.App.Payments.Queries;
using TakeoutSaaS.Domain.Payments.Repositories;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Payments.Handlers;

/// <summary>
/// 支付记录列表查询处理器。
/// </summary>
public sealed class SearchPaymentsQueryHandler(
    IPaymentRepository paymentRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<SearchPaymentsQuery, PagedResult<PaymentDto>>
{
    private readonly IPaymentRepository _paymentRepository = paymentRepository;
    private readonly ITenantProvider _tenantProvider = tenantProvider;

    /// <inheritdoc />
    public async Task<PagedResult<PaymentDto>> Handle(SearchPaymentsQuery request, CancellationToken cancellationToken)
    {
        var tenantId = _tenantProvider.GetCurrentTenantId();
        var payments = await _paymentRepository.SearchAsync(tenantId, request.Status, cancellationToken);

        if (request.OrderId.HasValue)
        {
            payments = payments.Where(x => x.OrderId == request.OrderId.Value).ToList();
        }

        var sorted = ApplySorting(payments, request.SortBy, request.SortDescending);
        var paged = sorted
            .Skip((request.Page - 1) * request.PageSize)
            .Take(request.PageSize)
            .ToList();

        var items = paged.Select(payment => new PaymentDto
        {
            Id = payment.Id,
            TenantId = payment.TenantId,
            OrderId = payment.OrderId,
            Method = payment.Method,
            Status = payment.Status,
            Amount = payment.Amount,
            TradeNo = payment.TradeNo,
            ChannelTransactionId = payment.ChannelTransactionId,
            PaidAt = payment.PaidAt,
            Remark = payment.Remark,
            Payload = payment.Payload,
            CreatedAt = payment.CreatedAt
        }).ToList();

        return new PagedResult<PaymentDto>(items, request.Page, request.PageSize, payments.Count);
    }

    private static IOrderedEnumerable<Domain.Payments.Entities.PaymentRecord> ApplySorting(
        IReadOnlyCollection<Domain.Payments.Entities.PaymentRecord> payments,
        string? sortBy,
        bool sortDescending)
    {
        return sortBy?.ToLowerInvariant() switch
        {
            "paidat" => sortDescending ? payments.OrderByDescending(x => x.PaidAt) : payments.OrderBy(x => x.PaidAt),
            "status" => sortDescending ? payments.OrderByDescending(x => x.Status) : payments.OrderBy(x => x.Status),
            "amount" => sortDescending ? payments.OrderByDescending(x => x.Amount) : payments.OrderBy(x => x.Amount),
            _ => sortDescending ? payments.OrderByDescending(x => x.CreatedAt) : payments.OrderBy(x => x.CreatedAt)
        };
    }
}
