using System.Globalization;
using TakeoutSaaS.Application.App.Stores;
using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Infrastructure.App.Services;

/// <summary>
/// 门店费用计算服务实现。
/// </summary>
public sealed class StoreFeeCalculationService : IStoreFeeCalculationService
{
    /// <inheritdoc />
    public StoreFeeCalculationResultDto Calculate(StoreFee fee, StoreFeeCalculationRequestDto request)
    {
        // 1. 计算起送费满足情况
        var minimum = fee.MinimumOrderAmount;
        if (request.OrderAmount < minimum)
        {
            var shortfall = minimum - request.OrderAmount;
            var message = $"还差{shortfall.ToString("0.##", CultureInfo.InvariantCulture)}元起送";
            return new StoreFeeCalculationResultDto
            {
                OrderAmount = request.OrderAmount,
                MinimumOrderAmount = minimum,
                MeetsMinimum = false,
                Shortfall = shortfall,
                DeliveryFee = 0m,
                PackagingFee = 0m,
                PackagingFeeMode = fee.PackagingFeeMode,
                OrderPackagingFeeMode = fee.OrderPackagingFeeMode,
                TotalFee = 0m,
                TotalAmount = request.OrderAmount,
                Message = message
            };
        }

        // 2. (空行后) 计算配送费
        var deliveryFee = fee.BaseDeliveryFee;
        if (fee.FreeDeliveryThreshold.HasValue && request.OrderAmount >= fee.FreeDeliveryThreshold.Value)
        {
            deliveryFee = 0m;
        }

        // 3. (空行后) 计算打包费
        var packagingFee = 0m;
        IReadOnlyList<StoreFeeCalculationBreakdownDto>? breakdown = null;
        if (fee.PackagingFeeMode == PackagingFeeMode.Fixed)
        {
            if (fee.OrderPackagingFeeMode == OrderPackagingFeeMode.Tiered)
            {
                var tiers = StoreFeeTierHelper.Deserialize(fee.PackagingFeeTiersJson);
                if (tiers.Count == 0)
                {
                    throw new BusinessException(ErrorCodes.ValidationFailed, "阶梯打包费配置缺失");
                }
                packagingFee = ResolveTieredFee(request.OrderAmount, tiers);
            }
            else
            {
                packagingFee = fee.FixedPackagingFee;
            }
        }
        else
        {
            if (request.Items.Count == 0)
            {
                throw new BusinessException(ErrorCodes.ValidationFailed, "商品计费模式必须提供商品列表");
            }
            var list = new List<StoreFeeCalculationBreakdownDto>(request.Items.Count);
            foreach (var item in request.Items)
            {
                var subtotal = item.PackagingFee * item.Quantity;
                packagingFee += subtotal;
                list.Add(new StoreFeeCalculationBreakdownDto
                {
                    SkuId = item.SkuId,
                    Quantity = item.Quantity,
                    UnitFee = item.PackagingFee,
                    Subtotal = subtotal
                });
            }
            breakdown = list;
        }

        // 4. (空行后) 汇总结果
        var totalFee = deliveryFee + packagingFee;
        var totalAmount = request.OrderAmount + totalFee;
        return new StoreFeeCalculationResultDto
        {
            OrderAmount = request.OrderAmount,
            MinimumOrderAmount = minimum,
            MeetsMinimum = true,
            DeliveryFee = deliveryFee,
            PackagingFee = packagingFee,
            PackagingFeeMode = fee.PackagingFeeMode,
            OrderPackagingFeeMode = fee.OrderPackagingFeeMode,
            PackagingFeeBreakdown = breakdown,
            TotalFee = totalFee,
            TotalAmount = totalAmount
        };
    }

    private static decimal ResolveTieredFee(decimal orderAmount, IReadOnlyList<StoreFeeTierDto> tiers)
    {
        foreach (var tier in tiers)
        {
            if (orderAmount < tier.MinPrice)
            {
                continue;
            }

            if (!tier.MaxPrice.HasValue || orderAmount <= tier.MaxPrice.Value)
            {
                return tier.Fee;
            }
        }

        return tiers[^1].Fee;
    }
}
