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

namespace TakeoutSaaS.Application.App.Customers.Handlers;

/// <summary>
/// 客户画像查询处理器。
/// </summary>
public sealed class GetCustomerProfileQueryHandler(
    IOrderRepository orderRepository,
    IProductRepository productRepository,
    IDapperExecutor dapperExecutor,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetCustomerProfileQuery, CustomerProfileDto?>
{
    /// <inheritdoc />
    public async Task<CustomerProfileDto?> Handle(
        GetCustomerProfileQuery request,
        CancellationToken cancellationToken)
    {
        // 1. 参数与可见门店校验
        var customerKey = CustomerAnalyticsSupport.NormalizePhone(request.CustomerKey);
        if (string.IsNullOrWhiteSpace(customerKey) || request.VisibleStoreIds.Count == 0)
        {
            return null;
        }

        // 2. 加载客户聚合并定位目标客户
        var customers = await CustomerAnalyticsSupport.LoadCustomersAsync(
            orderRepository,
            dapperExecutor,
            tenantProvider,
            request.VisibleStoreIds,
            cancellationToken);

        var customer = customers.FirstOrDefault(item =>
            string.Equals(item.CustomerKey, customerKey, StringComparison.Ordinal));
        if (customer is null)
        {
            return null;
        }

        var tenantId = tenantProvider.GetCurrentTenantId();
        if (tenantId <= 0)
        {
            return null;
        }

        // 3. 加载订单明细并计算画像数据
        var orderIds = customer.Orders
            .Select(item => item.OrderId)
            .ToList();
        var itemsLookup = await orderRepository.GetItemsByOrderIdsAsync(orderIds, tenantId, cancellationToken);

        var topProducts = CustomerAnalyticsSupport.BuildTopProducts(itemsLookup, orderIds, 5);
        var preferredCategories = await CustomerAnalyticsSupport.ResolvePreferredCategoriesAsync(
            productRepository,
            tenantId,
            itemsLookup,
            orderIds,
            cancellationToken);
        var preferredDelivery = CustomerAnalyticsSupport.ResolvePreferredDelivery(customer.Orders);
        var preferredPaymentMethod = await CustomerAnalyticsSupport.ResolvePreferredPaymentMethodAsync(
            orderRepository,
            tenantId,
            customer.Orders,
            cancellationToken);
        var preferredOrderPeaks = CustomerAnalyticsSupport.ResolvePreferredOrderPeaks(customer.Orders);
        var recentOrders = CustomerAnalyticsSupport.BuildRecentOrders(customer.Orders, itemsLookup, 5);
        var trend = CustomerAnalyticsSupport.BuildMonthlyTrend(customer.Orders, DateTime.UtcNow, 12);
        var repurchaseRatePercent = CustomerAnalyticsSupport.ToRatePercent(
            Math.Max(0, customer.OrderCount - 1),
            customer.OrderCount);
        var averageOrderIntervalDays = CustomerAnalyticsSupport.CalculateAverageIntervalDays(customer.Orders);

        return new CustomerProfileDto
        {
            CustomerKey = customer.CustomerKey,
            Name = customer.Name,
            PhoneMasked = customer.PhoneMasked,
            RegisteredAt = customer.RegisteredAt,
            FirstOrderAt = customer.FirstOrderAt,
            Source = customer.Source,
            Tags = customer.Tags,
            Member = customer.Member,
            TotalOrders = customer.OrderCount,
            TotalAmount = customer.TotalAmount,
            AverageAmount = customer.AverageAmount,
            RepurchaseRatePercent = repurchaseRatePercent,
            AverageOrderIntervalDays = averageOrderIntervalDays,
            Preference = new CustomerPreferenceDto
            {
                PreferredCategories = preferredCategories,
                PreferredOrderPeaks = preferredOrderPeaks,
                PreferredDelivery = preferredDelivery,
                PreferredPaymentMethod = preferredPaymentMethod,
                AverageDeliveryDistance = string.Empty
            },
            TopProducts = topProducts,
            Trend = trend,
            RecentOrders = recentOrders
        };
    }
}
