using MediatR;
using TakeoutSaaS.Application.App.Members.Dto;
using TakeoutSaaS.Application.App.Members.Queries;
using TakeoutSaaS.Domain.Membership.Repositories;
using TakeoutSaaS.Domain.Orders.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Members.Handlers;

/// <summary>
/// 会员详情查询处理器。
/// </summary>
public sealed class GetMemberDetailQueryHandler(
    IMemberRepository memberRepository,
    IOrderRepository orderRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetMemberDetailQuery, MemberDetailDto?>
{
    /// <inheritdoc />
    public async Task<MemberDetailDto?> Handle(
        GetMemberDetailQuery request,
        CancellationToken cancellationToken)
    {
        if (request.VisibleStoreIds.Count == 0)
        {
            return null;
        }

        var context = await MemberCenterSupport.LoadMemberContextAsync(
            memberRepository,
            orderRepository,
            tenantProvider,
            request.VisibleStoreIds,
            cancellationToken);

        var aggregate = context.Aggregates.FirstOrDefault(item => item.MemberId == request.MemberId);
        if (aggregate is null)
        {
            return null;
        }

        var tenantId = tenantProvider.GetCurrentTenantId();
        var tags = await memberRepository.GetProfileTagsAsync(tenantId, aggregate.MemberId, cancellationToken);

        var recentOrders = aggregate.Metrics.Orders
            .OrderByDescending(item => item.OrderedAt)
            .ThenByDescending(item => item.OrderId)
            .Take(3)
            .Select(item => new MemberRecentOrderDto
            {
                OrderedAt = item.OrderedAt,
                OrderNo = item.OrderNo,
                Amount = decimal.Round(item.Amount, 2, MidpointRounding.AwayFromZero),
                StatusText = MemberCenterSupport.ResolveOrderStatusText(item.Status)
            })
            .ToList();

        var averageAmount = aggregate.Metrics.TotalOrderCount <= 0
            ? 0
            : decimal.Round(aggregate.Metrics.TotalAmount / aggregate.Metrics.TotalOrderCount, 2, MidpointRounding.AwayFromZero);

        return new MemberDetailDto
        {
            MemberId = aggregate.MemberId,
            Name = aggregate.Name,
            AvatarText = aggregate.AvatarText,
            AvatarColor = aggregate.AvatarColor,
            MobileMasked = aggregate.MobileMasked,
            JoinedAt = aggregate.JoinedAt,
            TierId = aggregate.Tier?.Id,
            TierName = aggregate.Tier?.Name ?? string.Empty,
            TierColorHex = aggregate.Tier?.ColorHex ?? "#999999",
            TotalAmount = decimal.Round(aggregate.Metrics.TotalAmount, 2, MidpointRounding.AwayFromZero),
            OrderCount = aggregate.Metrics.TotalOrderCount,
            AverageAmount = averageAmount,
            StoredBalance = aggregate.Profile.StoredBalance,
            StoredRechargeBalance = aggregate.Profile.StoredRechargeBalance,
            StoredGiftBalance = aggregate.Profile.StoredGiftBalance,
            PointsBalance = Math.Max(0, aggregate.Profile.PointsBalance),
            Tags = tags.Select(item => item.TagName).ToList(),
            RecentOrders = recentOrders
        };
    }
}
