package com.ruoyi.web.modules.order.support;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.account.domain.BizMemberAddress;
import com.ruoyi.web.modules.freight.constant.FreightTemplateConstants;
import com.ruoyi.web.modules.freight.facade.IFreightTemplateFacade;
import com.ruoyi.web.modules.goods.domain.BizGoodsFreight;
import com.ruoyi.web.modules.goods.mapper.BizGoodsFreightMapper;
import com.ruoyi.web.modules.goods.vo.GoodsServiceSnapshotVO;
import com.ruoyi.web.modules.order.constant.CheckoutConstants;
import com.ruoyi.web.modules.order.constant.OrderConstants;
import com.ruoyi.web.modules.order.mapper.BizOrderMapper;
import com.ruoyi.web.modules.region.domain.BizRegion;
import com.ruoyi.web.modules.region.mapper.BizRegionMapper;

/**
 * 确认订单金额、地址、运费工具
 */
@Component
public class CheckoutSupport
{
    public static final BigDecimal DEFAULT_KG_PER_PIECE = BigDecimal.ONE;

    @Autowired
    private BizGoodsFreightMapper goodsFreightMapper;

    @Autowired
    private IFreightTemplateFacade freightTemplateFacade;

    @Autowired
    private BizRegionMapper regionMapper;

    @Autowired
    private BizOrderMapper orderMapper;

    public BigDecimal sumGoodsAmount(List<CheckoutLineModel> lines)
    {
        BigDecimal total = BigDecimal.ZERO;
        if (lines == null)
        {
            return total.setScale(2, RoundingMode.HALF_UP);
        }
        for (CheckoutLineModel line : lines)
        {
            if (line.getSubtotal() != null)
            {
                total = total.add(line.getSubtotal());
            }
        }
        return total.setScale(2, RoundingMode.HALF_UP);
    }

    public BigDecimal calcFreightSingle(Long shopId, Long goodsId, int quantity, Integer provinceId,
            BigDecimal goodsAmount)
    {
        CheckoutLineModel line = new CheckoutLineModel();
        line.setGoodsId(goodsId);
        line.setQuantity(quantity);
        return calcFreight(shopId, java.util.Collections.singletonList(line), provinceId, goodsAmount);
    }

    public BigDecimal calcFreight(Long shopId, List<CheckoutLineModel> lines, Integer provinceId,
            BigDecimal goodsAmount)
    {
        if (lines == null || lines.isEmpty())
        {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
        BigDecimal fixedTotal = BigDecimal.ZERO;
        Map<Long, TemplateGroup> templateGroups = new LinkedHashMap<>();
        for (CheckoutLineModel line : lines)
        {
            BizGoodsFreight freight = goodsFreightMapper.selectByGoodsId(line.getGoodsId());
            if (freight == null)
            {
                throw new ServiceException(CheckoutConstants.MSG_FREIGHT_NOT_CONFIG);
            }
            if (FreightTemplateConstants.FREIGHT_TYPE_FIXED.equals(freight.getFreightType()))
            {
                if (freight.getFixedAmount() == null)
                {
                    throw new ServiceException(CheckoutConstants.MSG_FREIGHT_NOT_CONFIG);
                }
                fixedTotal = fixedTotal.add(freight.getFixedAmount());
                continue;
            }
            if (FreightTemplateConstants.FREIGHT_TYPE_TEMPLATE.equals(freight.getFreightType()))
            {
                if (freight.getFreightTemplateId() == null)
                {
                    throw new ServiceException(CheckoutConstants.MSG_FREIGHT_NOT_CONFIG);
                }
                TemplateGroup group = templateGroups.computeIfAbsent(freight.getFreightTemplateId(),
                        id -> new TemplateGroup());
                int qty = line.getQuantity() != null ? line.getQuantity() : 0;
                group.pieceCount = group.pieceCount.add(BigDecimal.valueOf(qty));
                group.weightKg = group.weightKg.add(DEFAULT_KG_PER_PIECE.multiply(BigDecimal.valueOf(qty)));
                continue;
            }
            throw new ServiceException(CheckoutConstants.MSG_FREIGHT_NOT_CONFIG);
        }
        BigDecimal templateTotal = BigDecimal.ZERO;
        for (Map.Entry<Long, TemplateGroup> entry : templateGroups.entrySet())
        {
            TemplateGroup group = entry.getValue();
            BigDecimal part = freightTemplateFacade.calcFreight(entry.getKey(), shopId, provinceId,
                    group.pieceCount, group.weightKg, goodsAmount);
            templateTotal = templateTotal.add(part != null ? part : BigDecimal.ZERO);
        }
        return fixedTotal.add(templateTotal).setScale(2, RoundingMode.HALF_UP);
    }

    public String buildFreightDesc(Long shopId, List<CheckoutLineModel> lines, BigDecimal freightAmount,
            BigDecimal goodsAmount)
    {
        if (freightAmount == null || freightAmount.compareTo(BigDecimal.ZERO) <= 0)
        {
            return "包邮";
        }
        List<String> parts = new ArrayList<>();
        if (lines != null)
        {
            for (CheckoutLineModel line : lines)
            {
                BizGoodsFreight freight = goodsFreightMapper.selectByGoodsId(line.getGoodsId());
                if (freight == null)
                {
                    continue;
                }
                if (FreightTemplateConstants.FREIGHT_TYPE_FIXED.equals(freight.getFreightType())
                        && freight.getFixedAmount() != null)
                {
                    parts.add("运费 ¥" + freight.getFixedAmount().setScale(2, RoundingMode.HALF_UP));
                }
                else if (FreightTemplateConstants.FREIGHT_TYPE_TEMPLATE.equals(freight.getFreightType())
                        && freight.getFreightTemplateId() != null)
                {
                    String desc = freightTemplateFacade.buildFreightDesc(freight.getFreightTemplateId(), shopId);
                    if (StringUtils.isNotEmpty(desc))
                    {
                        parts.add(desc);
                    }
                }
            }
        }
        if (parts.isEmpty())
        {
            return "运费 ¥" + freightAmount.setScale(2, RoundingMode.HALF_UP);
        }
        return String.join("；", parts);
    }

    public String buildLineFreightDesc(BizGoodsFreight freight, Long shopId)
    {
        if (freight == null)
        {
            return "";
        }
        if (FreightTemplateConstants.FREIGHT_TYPE_FIXED.equals(freight.getFreightType()))
        {
            if (freight.getFixedAmount() == null)
            {
                return "";
            }
            return "运费 ¥" + freight.getFixedAmount().setScale(2, RoundingMode.HALF_UP);
        }
        if (FreightTemplateConstants.FREIGHT_TYPE_TEMPLATE.equals(freight.getFreightType())
                && freight.getFreightTemplateId() != null)
        {
            return freightTemplateFacade.buildFreightDesc(freight.getFreightTemplateId(), shopId);
        }
        return "";
    }

    public Integer resolveProvinceId(BizMemberAddress address)
    {
        if (address == null || StringUtils.isEmpty(address.getRegionCode()))
        {
            return null;
        }
        try
        {
            BizRegion region = regionMapper.selectByCode(Integer.parseInt(address.getRegionCode().trim()));
            while (region != null && region.getType() != null
                    && region.getType() != FreightTemplateConstants.REGION_TYPE_PROVINCE)
            {
                if (region.getPid() == null || region.getPid() == 0)
                {
                    break;
                }
                region = regionMapper.selectById(region.getPid());
            }
            return region != null ? region.getId() : null;
        }
        catch (NumberFormatException ex)
        {
            return null;
        }
    }

    public String buildConsigneeAddress(BizMemberAddress address)
    {
        String region = address.getRegionName() != null ? address.getRegionName().trim() : "";
        String detail = address.getDetailAddress() != null ? address.getDetailAddress().trim() : "";
        if (StringUtils.isEmpty(region))
        {
            return detail;
        }
        if (StringUtils.isEmpty(detail))
        {
            return region;
        }
        return region + " " + detail;
    }

    public String buildServiceDesc(List<GoodsServiceSnapshotVO> services)
    {
        if (services == null || services.isEmpty())
        {
            return "";
        }
        List<String> names = new ArrayList<>();
        for (GoodsServiceSnapshotVO service : services)
        {
            if (service != null && StringUtils.isNotEmpty(service.getServiceName()))
            {
                names.add(service.getServiceName());
            }
        }
        return String.join("、", names);
    }

    public String nextOrderNo(Date now)
    {
        String datePart = new SimpleDateFormat("yyyyMMdd").format(now);
        String prefix = "O" + datePart;
        String maxNo = orderMapper.selectMaxOrderNoByPrefix(prefix);
        int seq = 1;
        if (StringUtils.isNotEmpty(maxNo) && maxNo.length() > prefix.length())
        {
            try
            {
                seq = Integer.parseInt(maxNo.substring(prefix.length())) + 1;
            }
            catch (NumberFormatException ex)
            {
                seq = 1;
            }
        }
        return prefix + String.format("%06d", seq);
    }

    public void assertSameShop(List<CheckoutLineModel> lines)
    {
        if (lines == null || lines.isEmpty())
        {
            throw new ServiceException(CheckoutConstants.MSG_CART_ITEMS_REQUIRED);
        }
        Long shopId = lines.get(0).getShopId();
        for (CheckoutLineModel line : lines)
        {
            if (line.getShopId() == null || !line.getShopId().equals(shopId))
            {
                throw new ServiceException(CheckoutConstants.MSG_CROSS_SHOP);
            }
        }
    }

    public Map<String, Object> mockWechatPayParams()
    {
        Map<String, Object> params = new HashMap<>();
        params.put("mock", true);
        return params;
    }

    public void assertPendingPay(com.ruoyi.web.modules.order.domain.BizOrder order)
    {
        if (order == null || !OrderConstants.STATUS_PENDING_PAY.equals(order.getOrderStatus()))
        {
            throw new ServiceException(OrderConstants.MSG_PENDING_PAY_ONLY);
        }
    }

    public void assertNotExpired(com.ruoyi.web.modules.order.domain.BizOrder order, Date now)
    {
        if (order.getPayExpireTime() != null && order.getPayExpireTime().before(now))
        {
            throw new ServiceException(OrderConstants.MSG_PAY_EXPIRED);
        }
    }

    private static final class TemplateGroup
    {
        private BigDecimal pieceCount = BigDecimal.ZERO;

        private BigDecimal weightKg = BigDecimal.ZERO;
    }
}
