using MediatR;
using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Enums;
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 SaveProductSpecTemplateCommandHandler(
    IProductRepository productRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<SaveProductSpecTemplateCommand, ProductSpecTemplateItemDto>
{
    /// <inheritdoc />
    public async Task<ProductSpecTemplateItemDto> Handle(SaveProductSpecTemplateCommand request, CancellationToken cancellationToken)
    {
        // 1. 读取并校验基础输入。
        var tenantId = tenantProvider.GetCurrentTenantId();
        var normalizedName = request.Name.Trim();
        if (string.IsNullOrWhiteSpace(normalizedName))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "模板名称不能为空");
        }

        if (!ProductSpecTemplateMapping.TryParseStatus(request.Status, out var isEnabled))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "status 参数不合法");
        }

        if (!ProductSpecTemplateMapping.TryParseTemplateType(request.Type, out var templateType))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "type 参数不合法");
        }

        if (!ProductSpecTemplateMapping.TryParseSelectionType(request.SelectionType, out var selectionType))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "selectionType 参数不合法");
        }

        var normalizedValues = NormalizeValues(request.Values);
        if (normalizedValues.Count == 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "请至少添加一个选项");
        }

        var normalizedMinSelect = request.IsRequired ? 1 : 0;
        var normalizedMaxSelect = selectionType == AttributeSelectionType.Single
            ? 1
            : Math.Max(1, normalizedValues.Count);

        // 2. 校验同门店模板名称唯一。
        var isDuplicate = await productRepository.ExistsSpecTemplateNameAsync(
            tenantId,
            request.StoreId,
            normalizedName,
            request.SpecId,
            cancellationToken);
        if (isDuplicate)
        {
            throw new BusinessException(ErrorCodes.Conflict, "模板名称已存在");
        }

        var normalizedProductIds = request.ProductIds
            .Where(id => id > 0)
            .Distinct()
            .ToList();
        var validProductIds = await productRepository.FilterExistingProductIdsAsync(
            tenantId,
            request.StoreId,
            normalizedProductIds,
            cancellationToken);

        // 3. 创建或更新模板主记录。
        ProductSpecTemplate template;
        var isCreate = !request.SpecId.HasValue;
        if (isCreate)
        {
            template = new ProductSpecTemplate
            {
                StoreId = request.StoreId,
                Name = normalizedName,
                Description = string.Empty,
                TemplateType = templateType,
                SelectionType = selectionType,
                IsRequired = request.IsRequired,
                MinSelect = normalizedMinSelect,
                MaxSelect = normalizedMaxSelect,
                SortOrder = Math.Max(1, request.Sort),
                IsEnabled = isEnabled
            };
            await productRepository.AddSpecTemplateAsync(template, cancellationToken);
            await productRepository.SaveChangesAsync(cancellationToken);
        }
        else
        {
            var existing = await productRepository.FindSpecTemplateByIdAsync(
                request.SpecId!.Value,
                tenantId,
                cancellationToken);
            if (existing is null || existing.StoreId != request.StoreId)
            {
                throw new BusinessException(ErrorCodes.NotFound, "模板不存在");
            }

            template = existing;
            template.Name = normalizedName;
            template.TemplateType = templateType;
            template.SelectionType = selectionType;
            template.IsRequired = request.IsRequired;
            template.MinSelect = normalizedMinSelect;
            template.MaxSelect = normalizedMaxSelect;
            template.SortOrder = Math.Max(1, request.Sort);
            template.IsEnabled = isEnabled;
            await productRepository.UpdateSpecTemplateAsync(template, cancellationToken);
        }

        // 4. 替换模板选项与关联商品。
        await productRepository.RemoveSpecTemplateOptionsAsync(template.Id, tenantId, cancellationToken);
        await productRepository.RemoveSpecTemplateProductsAsync(template.Id, tenantId, request.StoreId, cancellationToken);

        var optionEntities = normalizedValues
            .Select(value => new ProductSpecTemplateOption
            {
                TemplateId = template.Id,
                Name = value.Name,
                ExtraPrice = value.ExtraPrice,
                Stock = 999,
                IsEnabled = true,
                SortOrder = value.Sort
            })
            .ToList();
        if (optionEntities.Count > 0)
        {
            await productRepository.AddSpecTemplateOptionsAsync(optionEntities, cancellationToken);
        }

        var relationEntities = validProductIds
            .Select(productId => new ProductSpecTemplateProduct
            {
                StoreId = request.StoreId,
                TemplateId = template.Id,
                ProductId = productId
            })
            .ToList();
        if (relationEntities.Count > 0)
        {
            await productRepository.AddSpecTemplateProductsAsync(relationEntities, cancellationToken);
        }

        await productRepository.SaveChangesAsync(cancellationToken);

        // 5. 回读并返回最新快照。
        var options = await productRepository.GetSpecTemplateOptionsByTemplateIdsAsync([template.Id], tenantId, cancellationToken);
        var relations = await productRepository.GetSpecTemplateProductsByTemplateIdsAsync([template.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(template, optionsLookup, productIdsLookup);
    }

    private static IReadOnlyList<NormalizedSpecValue> NormalizeValues(IReadOnlyList<SaveProductSpecTemplateValueCommand>? values)
    {
        var source = values ?? [];
        var normalized = source
            .Select((item, index) => new NormalizedSpecValue
            {
                Name = item.Name.Trim(),
                ExtraPrice = item.ExtraPrice,
                Sort = item.Sort > 0 ? item.Sort : index + 1
            })
            .Where(item => !string.IsNullOrWhiteSpace(item.Name))
            .OrderBy(item => item.Sort)
            .ToList();

        var duplicate = normalized
            .GroupBy(item => item.Name, StringComparer.OrdinalIgnoreCase)
            .Any(group => group.Count() > 1);
        if (duplicate)
        {
            throw new BusinessException(ErrorCodes.Conflict, "模板选项名称重复");
        }

        for (var index = 0; index < normalized.Count; index++)
        {
            normalized[index].Sort = index + 1;
        }

        return normalized;
    }

    private sealed class NormalizedSpecValue
    {
        public decimal ExtraPrice { get; init; }

        public string Name { get; init; } = string.Empty;

        public int Sort { get; set; }
    }
}
