using MediatR;
using TakeoutSaaS.Application.App.Customers.Dto;
using TakeoutSaaS.Application.App.Customers.Queries;
using TakeoutSaaS.Domain.Orders.Repositories;
using TakeoutSaaS.Shared.Abstractions.Data;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Customers.Handlers;

/// <summary>
/// 客群明细查询处理器。
/// </summary>
public sealed class GetCustomerAnalysisSegmentListQueryHandler(
    IOrderRepository orderRepository,
    IDapperExecutor dapperExecutor,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetCustomerAnalysisSegmentListQuery, CustomerAnalysisSegmentListResultDto>
{
    /// <inheritdoc />
    public async Task<CustomerAnalysisSegmentListResultDto> Handle(
        GetCustomerAnalysisSegmentListQuery request,
        CancellationToken cancellationToken)
    {
        var page = Math.Max(1, request.Page);
        var pageSize = Math.Clamp(request.PageSize, 1, 200);
        var periodDays = Math.Clamp(request.PeriodDays, 7, 365);
        var normalizedSegmentCode = CustomerAnalysisSegmentSupport.NormalizeSegmentCode(request.SegmentCode);
        var segmentMeta = CustomerAnalysisSegmentSupport.ResolveSegmentMeta(normalizedSegmentCode);

        if (request.VisibleStoreIds.Count == 0)
        {
            return new CustomerAnalysisSegmentListResultDto
            {
                SegmentCode = segmentMeta.SegmentCode,
                SegmentTitle = segmentMeta.SegmentTitle,
                SegmentDescription = segmentMeta.SegmentDescription,
                Page = page,
                PageSize = pageSize,
                TotalCount = 0,
                Items = []
            };
        }

        var customers = await CustomerAnalyticsSupport.LoadCustomersAsync(
            orderRepository,
            dapperExecutor,
            tenantProvider,
            request.VisibleStoreIds,
            cancellationToken);

        var nowUtc = DateTime.UtcNow;
        var segmentCustomers = CustomerAnalysisSegmentSupport.FilterBySegment(
            customers,
            normalizedSegmentCode,
            nowUtc,
            periodDays);

        var keywordFiltered = CustomerAnalysisSegmentSupport.ApplyKeyword(
            segmentCustomers,
            request.Keyword);

        var sortedCustomers = keywordFiltered
            .OrderByDescending(item => item.TotalAmount)
            .ThenByDescending(item => item.OrderCount)
            .ThenByDescending(item => item.LastOrderAt)
            .ThenBy(item => item.CustomerKey, StringComparer.Ordinal)
            .ToList();

        var pagedItems = sortedCustomers
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(item => new CustomerAnalysisSegmentListItemDto
            {
                CustomerKey = item.CustomerKey,
                Name = item.Name,
                PhoneMasked = item.PhoneMasked,
                AvatarText = item.AvatarText,
                AvatarColor = item.AvatarColor,
                Tags = item.Tags,
                IsMember = item.Member.IsMember,
                MemberTierName = item.Member.TierName,
                TotalAmount = item.TotalAmount,
                OrderCount = item.OrderCount,
                AverageAmount = item.AverageAmount,
                RegisteredAt = item.RegisteredAt,
                LastOrderAt = item.LastOrderAt,
                IsDimmed = item.IsDimmed
            })
            .ToList();

        return new CustomerAnalysisSegmentListResultDto
        {
            SegmentCode = segmentMeta.SegmentCode,
            SegmentTitle = segmentMeta.SegmentTitle,
            SegmentDescription = segmentMeta.SegmentDescription,
            Items = pagedItems,
            Page = page,
            PageSize = pageSize,
            TotalCount = sortedCustomers.Count
        };
    }
}
