using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Application.App.Products.Queries;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Enums;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Products.Handlers;

/// <summary>
/// 门店菜单查询处理器。
/// </summary>
public sealed class GetStoreMenuQueryHandler(
    IProductRepository productRepository,
    ITenantProvider tenantProvider,
    ILogger<GetStoreMenuQueryHandler> logger)
    : IRequestHandler<GetStoreMenuQuery, StoreMenuDto>
{
    /// <inheritdoc />
    public async Task<StoreMenuDto> Handle(GetStoreMenuQuery request, CancellationToken cancellationToken)
    {
        // 1. 准备上下文
        var tenantId = tenantProvider.GetCurrentTenantId();
        var updatedAfterUtc = request.UpdatedAfter?.ToUniversalTime();
        // 2. 获取分类
        var categories = await productRepository.GetCategoriesByStoreAsync(tenantId, request.StoreId, true, cancellationToken);
        // 3. 读取上架商品（支持增量）
        var products = await productRepository.SearchAsync(tenantId, request.StoreId, null, ProductStatus.OnSale, cancellationToken, updatedAfterUtc);
        if (products.Count == 0)
        {
            logger.LogInformation("门店 {StoreId} 没有上架商品，返回空菜单", request.StoreId);
            return new StoreMenuDto
            {
                StoreId = request.StoreId,
                GeneratedAt = DateTime.UtcNow,
                UpdatedAfter = updatedAfterUtc,
                Categories = categories
                    .OrderBy(x => x.SortOrder)
                    .Select(category => new ProductCategoryMenuDto
                    {
                        Id = category.Id,
                        StoreId = category.StoreId,
                        Name = category.Name,
                        Description = category.Description,
                        SortOrder = category.SortOrder,
                        IsEnabled = category.IsEnabled,
                        Products = []
                    })
                    .ToList()
            };
        }

        // 4. 并发加载子表数据
        var productIds = products.Select(x => x.Id).ToList();
        var skusTask = productRepository.GetSkusByProductIdsAsync(productIds, tenantId, cancellationToken);
        var attributeGroupsTask = productRepository.GetAttributeGroupsByProductIdsAsync(productIds, tenantId, cancellationToken);
        var addonGroupsTask = productRepository.GetAddonGroupsByProductIdsAsync(productIds, tenantId, cancellationToken);
        var mediaTask = productRepository.GetMediaAssetsByProductIdsAsync(productIds, tenantId, cancellationToken);
        var pricingTask = productRepository.GetPricingRulesByProductIdsAsync(productIds, tenantId, cancellationToken);
        await Task.WhenAll(skusTask, attributeGroupsTask, addonGroupsTask, mediaTask, pricingTask);
        var attributeGroups = await attributeGroupsTask;
        var addonGroups = await addonGroupsTask;
        // 批量读取规格与加料选项
        var attributeOptionsTask = attributeGroups.Count == 0
            ? Task.FromResult<IReadOnlyList<ProductAttributeOption>>(Array.Empty<ProductAttributeOption>())
            : productRepository.GetAttributeOptionsByGroupIdsAsync(attributeGroups.Select(x => x.Id).ToList(), tenantId, cancellationToken);
        var addonOptionsTask = addonGroups.Count == 0
            ? Task.FromResult<IReadOnlyList<ProductAddonOption>>(Array.Empty<ProductAddonOption>())
            : productRepository.GetAddonOptionsByGroupIdsAsync(addonGroups.Select(x => x.Id).ToList(), tenantId, cancellationToken);
        await Task.WhenAll(attributeOptionsTask, addonOptionsTask);

        // 5. 建立查找表
        var skuLookup = (await skusTask).ToLookup(x => x.ProductId);
        var attrGroupLookup = attributeGroups.ToLookup(x => x.ProductId);
        var attrOptionLookup = (await attributeOptionsTask).ToLookup(x => x.AttributeGroupId);
        var addonGroupLookup = addonGroups.ToLookup(x => x.ProductId);
        var addonOptionLookup = (await addonOptionsTask).ToLookup(x => x.AddonGroupId);
        var mediaLookup = (await mediaTask).ToLookup(x => x.ProductId);
        var pricingLookup = (await pricingTask).ToLookup(x => x.ProductId);
        // 6. 组装商品详情
        var productDetails = products.ToDictionary(
            product => product.Id,
            product =>
            {
                var attributeDtos = attrGroupLookup[product.Id]
                    .Select(group => ProductMapping.ToDto(group, attrOptionLookup[group.Id].ToList()))
                    .ToList();
                var addonDtos = addonGroupLookup[product.Id]
                    .Select(group => ProductMapping.ToDto(group, addonOptionLookup[group.Id].ToList()))
                    .ToList();
                return new ProductDetailDto
                {
                    Product = ProductMapping.ToDto(product),
                    Skus = skuLookup[product.Id].Select(ProductMapping.ToDto).ToList(),
                    AttributeGroups = attributeDtos,
                    AddonGroups = addonDtos,
                    MediaAssets = mediaLookup[product.Id].Select(ProductMapping.ToDto).ToList(),
                    PricingRules = pricingLookup[product.Id].Select(ProductMapping.ToDto).ToList()
                };
            });
        // 7. 组装分类菜单
        var productsByCategory = products.ToLookup(x => x.CategoryId);
        var categoryMenu = categories
            .OrderBy(x => x.SortOrder)
            .Select(category =>
            {
                var categoryProducts = productsByCategory[category.Id]
                    .Select(p => productDetails[p.Id])
                    .ToList();
                return new ProductCategoryMenuDto
                {
                    Id = category.Id,
                    StoreId = category.StoreId,
                    Name = category.Name,
                    Description = category.Description,
                    SortOrder = category.SortOrder,
                    IsEnabled = category.IsEnabled,
                    Products = categoryProducts
                };
            })
            .ToList();
        return new StoreMenuDto
        {
            StoreId = request.StoreId,
            GeneratedAt = DateTime.UtcNow,
            UpdatedAfter = updatedAfterUtc,
            Categories = categoryMenu
        };
    }
}
