using MediatR;
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 CopyProductSpecTemplateCommandHandler(
    IProductRepository productRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<CopyProductSpecTemplateCommand, ProductSpecTemplateItemDto>
{
    /// <inheritdoc />
    public async Task<ProductSpecTemplateItemDto> Handle(CopyProductSpecTemplateCommand request, CancellationToken cancellationToken)
    {
        // 1. 读取源模板并校验门店归属。
        var tenantId = tenantProvider.GetCurrentTenantId();
        var source = await productRepository.FindSpecTemplateByIdAsync(request.SpecId, tenantId, cancellationToken);
        if (source is null || source.StoreId != request.StoreId)
        {
            throw new BusinessException(ErrorCodes.NotFound, "模板不存在");
        }

        // 2. 生成不冲突的新模板名称。
        var isDefaultCopyName = string.IsNullOrWhiteSpace(request.NewName);
        var baseName = isDefaultCopyName
            ? $"{source.Name}(副本)"
            : request.NewName!.Trim();
        if (string.IsNullOrWhiteSpace(baseName))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "模板名称不能为空");
        }

        var targetName = await BuildAvailableNameAsync(
            tenantId,
            request.StoreId,
            baseName,
            source.Name,
            isDefaultCopyName,
            cancellationToken);

        // 3. 创建模板主记录并落库获取 ID。
        var copiedTemplate = new ProductSpecTemplate
        {
            StoreId = request.StoreId,
            Name = targetName,
            TemplateType = source.TemplateType,
            SelectionType = source.SelectionType,
            IsRequired = source.IsRequired,
            SortOrder = source.SortOrder,
            IsEnabled = source.IsEnabled
        };
        await productRepository.AddSpecTemplateAsync(copiedTemplate, cancellationToken);
        await productRepository.SaveChangesAsync(cancellationToken);

        // 4. 复制选项与关联商品。
        var sourceOptions = await productRepository.GetSpecTemplateOptionsByTemplateIdsAsync(
            [source.Id],
            tenantId,
            cancellationToken);
        var sourceRelations = await productRepository.GetSpecTemplateProductsByTemplateIdsAsync(
            [source.Id],
            tenantId,
            request.StoreId,
            cancellationToken);

        if (sourceOptions.Count > 0)
        {
            var copiedOptions = sourceOptions
                .Select(option => new ProductSpecTemplateOption
                {
                    TemplateId = copiedTemplate.Id,
                    Name = option.Name,
                    ExtraPrice = option.ExtraPrice,
                    SortOrder = option.SortOrder
                })
                .ToList();
            await productRepository.AddSpecTemplateOptionsAsync(copiedOptions, cancellationToken);
        }

        if (sourceRelations.Count > 0)
        {
            var copiedRelations = sourceRelations
                .Select(relation => relation.ProductId)
                .Distinct()
                .Select(productId => new ProductSpecTemplateProduct
                {
                    StoreId = request.StoreId,
                    TemplateId = copiedTemplate.Id,
                    ProductId = productId
                })
                .ToList();
            await productRepository.AddSpecTemplateProductsAsync(copiedRelations, cancellationToken);
        }

        await productRepository.SaveChangesAsync(cancellationToken);

        // 5. 返回复制后的模板快照。
        var options = await productRepository.GetSpecTemplateOptionsByTemplateIdsAsync([copiedTemplate.Id], tenantId, cancellationToken);
        var relations = await productRepository.GetSpecTemplateProductsByTemplateIdsAsync([copiedTemplate.Id], tenantId, request.StoreId, cancellationToken);
        var optionsLookup = options
            .GroupBy(x => x.TemplateId)
            .ToDictionary(group => group.Key, group => group.OrderBy(item => item.SortOrder).ThenBy(item => item.Id).ToList());
        var productIdsLookup = relations
            .GroupBy(x => x.TemplateId)
            .ToDictionary(group => group.Key, group => group.Select(item => item.ProductId).ToList());

        return ProductSpecTemplateDtoFactory.ToDto(copiedTemplate, optionsLookup, productIdsLookup);
    }

    private async Task<string> BuildAvailableNameAsync(
        long tenantId,
        long storeId,
        string baseName,
        string sourceName,
        bool isDefaultCopyName,
        CancellationToken cancellationToken)
    {
        var candidate = baseName;
        var conflict = await productRepository.ExistsSpecTemplateNameAsync(tenantId, storeId, candidate, null, cancellationToken);
        if (!conflict)
        {
            return candidate;
        }

        for (var index = 2; index <= 999; index++)
        {
            candidate = isDefaultCopyName
                ? $"{sourceName}(副本{index})"
                : $"{baseName}({index})";

            conflict = await productRepository.ExistsSpecTemplateNameAsync(tenantId, storeId, candidate, null, cancellationToken);
            if (!conflict)
            {
                return candidate;
            }
        }

        throw new BusinessException(ErrorCodes.Conflict, "复制失败，模板名称冲突过多");
    }
}
