using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Products.Handlers;

/// <summary>
/// 替换加料处理器。
/// </summary>
public sealed class ReplaceProductAddonsCommandHandler(
    IProductRepository productRepository,
    ITenantProvider tenantProvider,
    ILogger<ReplaceProductAddonsCommandHandler> logger)
    : IRequestHandler<ReplaceProductAddonsCommand, IReadOnlyList<ProductAddonGroupDto>>
{
    /// <inheritdoc />
    public async Task<IReadOnlyList<ProductAddonGroupDto>> Handle(ReplaceProductAddonsCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验商品
        var tenantId = tenantProvider.GetCurrentTenantId();
        var product = await productRepository.FindByIdAsync(request.ProductId, tenantId, cancellationToken);
        if (product is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "商品不存在");
        }

        // 2. 校验组名唯一
        var names = request.AddonGroups.Select(x => x.Name.Trim()).ToList();
        if (names.Count != names.Distinct(StringComparer.OrdinalIgnoreCase).Count())
        {
            throw new BusinessException(ErrorCodes.Conflict, "加料组名称重复");
        }

        // 3. 替换
        await productRepository.RemoveAddonGroupsAsync(request.ProductId, tenantId, cancellationToken);
        // 重新插入组
        var groupEntities = request.AddonGroups.Select(g => new ProductAddonGroup
        {
            ProductId = request.ProductId,
            Name = g.Name.Trim(),
            MinSelect = g.MinSelect,
            MaxSelect = g.MaxSelect,
            SortOrder = g.SortOrder
        }).ToList();
        await productRepository.AddAddonGroupsAsync(groupEntities, [], cancellationToken);
        await productRepository.SaveChangesAsync(cancellationToken);
        // 重新建立组与请求的映射
        var groupIdLookup = groupEntities.Zip(request.AddonGroups, (entity, dto) => (entity, dto))
            .ToDictionary(x => x.dto, x => x.entity.Id);
        // 构建选项实体
        var optionEntities = request.AddonGroups
            .SelectMany(dto => dto.Options.Select(o => new ProductAddonOption
            {
                AddonGroupId = groupIdLookup[dto],
                Name = o.Name.Trim(),
                ExtraPrice = o.ExtraPrice,
                SortOrder = o.SortOrder
            }))
            .ToList();
        await productRepository.AddAddonGroupsAsync([], optionEntities, cancellationToken);
        await productRepository.SaveChangesAsync(cancellationToken);
        logger.LogInformation("替换商品 {ProductId} 加料组 {Count} 个", request.ProductId, groupEntities.Count);

        return groupEntities
            .Select(g => ProductMapping.ToDto(g, optionEntities.Where(o => o.AddonGroupId == g.Id).ToList()))
            .ToList();
    }
}
