package cn.iocoder.yudao.module.order.service.orderSplit;

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderItem.OrderItemDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderSplitItem.OrderSplitItemDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderWarehouseIn.OrderWarehouseInDO;
import cn.iocoder.yudao.module.order.dal.mysql.orderSplitItem.OrderSplitItemMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderWarehouseIn.OrderWarehouseInMapper;
import cn.iocoder.yudao.module.order.dto.OrderSplitWorthDto;
import cn.iocoder.yudao.module.order.service.order.OrderQueryService;
import cn.iocoder.yudao.module.order.vo.order.CostVO;
import cn.iocoder.yudao.module.order.vo.orderSplitItem.OrderSpiltItemSpecsRecordVO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.order.enums.ErrorCodeConstants.*;

/**
 * 订单拆单 Service 实现类
 *
 * @author yanghao
 */
@Service
@Validated
public class OrderSplitCheckServiceImpl implements OrderSplitCheckService {


    @Resource
    private OrderSplitItemMapper splitItemMapper;
    @Resource
    private OrderWarehouseInMapper orderWarehouseInMapper;
    @Resource
    private OrderQueryService orderQueryService;


    /**
     * 拆单数据强一致性校验
     *
     * @param sourceOrderItemDO 原订单项
     * @param orderItemId       订单项ID
     * @param allNum            原订单项总入仓箱数
     * @param quantity          原订单项总入仓数量
     * @param weight            原订单项总入仓重量
     * @param volume            原订单项总入仓体积
     * @param chargeWeight      原订单项总收费重量
     * @param chargeVolume      原订单项总收费体积
     * @param chargeQuantity    原订单项总收费数量
     */
    public void splitConsistencyCheck(OrderItemDO sourceOrderItemDO, Long orderItemId, int allNum, int quantity, BigDecimal weight,
                                      BigDecimal volume, BigDecimal chargeWeight, BigDecimal chargeVolume,
                                      BigDecimal chargeQuantity) {
        List<OrderSplitItemDO> orderSplitItemDOList = splitItemMapper.selectList(new LambdaQueryWrapperX<OrderSplitItemDO>()
                .eq(OrderSplitItemDO::getUsed, false)
                .eq(OrderSplitItemDO::getOrderItemId, orderItemId));
        if (CollectionUtil.isEmpty(orderSplitItemDOList)){
            throw exception(SPLIT_ORDER_ITEM_PROD_NOT_NULL, I18nMessage.getLang() == 0 ? sourceOrderItemDO.getProdTitleZh() : sourceOrderItemDO.getProdTitleEn());
        }
        consistencyCheck(allNum, quantity, weight, volume, chargeWeight, chargeVolume, chargeQuantity, orderSplitItemDOList);
    }

    @Override
    public void splitConsistencyCheck(List<OrderSplitItemDO> orderSplitItemDOList, int allNum, int quantity, BigDecimal weight, BigDecimal volume, BigDecimal chargeWeight, BigDecimal chargeVolume, BigDecimal chargeQuantity) {
        consistencyCheck(allNum, quantity, weight, volume, chargeWeight, chargeVolume, chargeQuantity, orderSplitItemDOList);
    }


    /**
     * @param allNum         原订单项总入仓箱数
     * @param quantity       原订单项总入仓数量
     * @param weight         原订单项总入仓重量
     * @param volume         原订单项总入仓体积
     * @param chargeWeight   原订单项总收费重量
     * @param chargeVolume   原订单项总收费体积
     * @param chargeQuantity 原订单项总收费数量
     */
    private void consistencyCheck(int allNum, int quantity, BigDecimal weight, BigDecimal volume,
                                  BigDecimal chargeWeight, BigDecimal chargeVolume, BigDecimal chargeQuantity,
                                  List<OrderSplitItemDO> orderSplitItemDOList) {
//        String titleZh = orderSplitItemDOList.stream().map(OrderSplitItemDO::getProdTitleZh).findFirst().orElse("");
//        String titleEn = orderSplitItemDOList.stream().map(OrderSplitItemDO::getProdTitleEn).findFirst().orElse("");
//        String title = I18nMessage.getLang() == 0 ? titleZh : titleEn;
        //当前子拆单总箱数、数量
        int splitAllNum = orderSplitItemDOList.stream().mapToInt(OrderSplitItemDO::getNum).sum();
        int numDifference = splitAllNum - allNum;
        if (numDifference != 0) {
            if (numDifference > 0) {
                throw exception(ORDER_SPLIT_ITEM_NUM_MANY_EXCEPTION,  numDifference);
            } else {
                throw exception(ORDER_SPLIT_ITEM_NUM_FEW_EXCEPTION, -numDifference);
            }
        }
        int splitAllQuantity = orderSplitItemDOList.stream().mapToInt(OrderSplitItemDO::getQuantity).sum();
        int quantityDifference = splitAllQuantity - quantity;
        if (quantityDifference != 0) {
            if (quantityDifference > 0) {
                throw exception(ORDER_SPLIT_ITEM_QUANTITY_MANY_EXCEPTION,  quantityDifference);
            } else {
                throw exception(ORDER_SPLIT_ITEM_QUANTITY_FEW_EXCEPTION, -quantityDifference);
            }
        }
        // 当前子拆单总入仓属性
        BigDecimal splitAllWeight = orderSplitItemDOList.stream().map(OrderSplitItemDO::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal weightDifference = splitAllWeight.subtract(weight);
        if (weightDifference.compareTo(BigDecimal.ZERO) != 0) {
            if (weightDifference.compareTo(BigDecimal.ZERO) > 0) {
                throw exception(ORDER_SPLIT_ITEM_WEIGHT_MANY_EXCEPTION, weightDifference.setScale(2, RoundingMode.HALF_UP));
            } else {
                throw exception(ORDER_SPLIT_ITEM_WEIGHT_FEW_EXCEPTION, weightDifference.negate().setScale(2, RoundingMode.HALF_UP));
            }
        }

        BigDecimal splitAllVolume = orderSplitItemDOList.stream().map(OrderSplitItemDO::getVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal volumeDifference = splitAllVolume.subtract(volume);
        if (volumeDifference.compareTo(BigDecimal.ZERO) != 0) {
            if (volumeDifference.compareTo(BigDecimal.ZERO) > 0) {
                throw exception(ORDER_SPLIT_ITEM_VOLUME_MANY_EXCEPTION,  volumeDifference.setScale(2, RoundingMode.HALF_UP));
            } else {
                throw exception(ORDER_SPLIT_ITEM_VOLUME_FEW_EXCEPTION, volumeDifference.negate().setScale(2, RoundingMode.HALF_UP));
            }
        }

        // 当前子拆单收费属性
        BigDecimal splitAllChargeWeight = orderSplitItemDOList.stream().map(OrderSplitItemDO::getChargeWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal chargeWeightDifference = splitAllChargeWeight.subtract(chargeWeight);
        if (chargeWeightDifference.compareTo(BigDecimal.ZERO) != 0) {
            if (chargeWeightDifference.compareTo(BigDecimal.ZERO) > 0) {
                throw exception(ORDER_SPLIT_ITEM_CHARGE_WEIGHT_MANY_EXCEPTION, chargeWeightDifference.setScale(2, RoundingMode.HALF_UP));
            } else {
                throw exception(ORDER_SPLIT_ITEM_CHARGE_WEIGHT_FEW_EXCEPTION, chargeWeightDifference.negate().setScale(2, RoundingMode.HALF_UP));
            }
        }
        BigDecimal splitAllChargeVolume = orderSplitItemDOList.stream().map(OrderSplitItemDO::getChargeVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal chargeVolumeDifference = splitAllChargeVolume.subtract(chargeVolume);
        if (chargeVolumeDifference.compareTo(BigDecimal.ZERO) != 0) {
            if (chargeVolumeDifference.compareTo(BigDecimal.ZERO) > 0) {
                throw exception(ORDER_SPLIT_ITEM_CHARGE_VOLUME_MANY_EXCEPTION, chargeVolumeDifference.setScale(2, RoundingMode.HALF_UP));
            } else {
                throw exception(ORDER_SPLIT_ITEM_CHARGE_VOLUME_FEW_EXCEPTION, chargeVolumeDifference.negate().setScale(2, RoundingMode.HALF_UP));
            }
        }
        BigDecimal splitAllChargeQuantity = orderSplitItemDOList.stream().map(OrderSplitItemDO::getChargeQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal chargeQuantityDifference = splitAllChargeQuantity.subtract(chargeQuantity);
        if (chargeQuantityDifference.compareTo(BigDecimal.ZERO) != 0) {
            if (chargeQuantityDifference.compareTo(BigDecimal.ZERO) > 0) {
                throw exception(ORDER_SPLIT_ITEM_QUANTITY_MANY_EXCEPTION,  chargeQuantityDifference.setScale(2, RoundingMode.HALF_UP));
            } else {
                throw exception(ORDER_SPLIT_ITEM_QUANTITY_FEW_EXCEPTION, chargeQuantityDifference.negate().setScale(2, RoundingMode.HALF_UP));
            }
        }


        Map<Long, List<OrderSplitItemDO>> orderSplitItemMap = orderSplitItemDOList.stream().collect(Collectors.groupingBy(OrderSplitItemDO::getOrderItemId));
        // 校验总的入仓记录与原单入仓记录是否一致
        for (Map.Entry<Long, List<OrderSplitItemDO>> entry : orderSplitItemMap.entrySet()) {
            // 获取单个品名的入仓记录
            List<OrderSpiltItemSpecsRecordVO> specsRecordVOList = new ArrayList<>();
            for (OrderSplitItemDO splitItemDO : entry.getValue()) {
                if (StringUtils.isNotBlank(splitItemDO.getSpecsRecord())) {
                    specsRecordVOList.addAll(splitItemDO.getSpecsRecordVOList());
                }
            }
            // 获取订单项的全部入仓记录
            List<OrderWarehouseInDO> warehouseInDOList = orderWarehouseInMapper.selectList(new LambdaQueryWrapper<OrderWarehouseInDO>()
                    .eq(OrderWarehouseInDO::getOrderItemId, entry.getKey()));

            checkWarehouseInId(specsRecordVOList, warehouseInDOList);
        }
    }


    @Override
    public void splitWorthConsistencyCheck(List<OrderSplitItemDO> orderAllSplitItemDOList, BigDecimal worth) {
        BigDecimal splitAllWorth = orderAllSplitItemDOList.stream().map(OrderSplitItemDO::getWorth).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal worthDifference = splitAllWorth.subtract(worth);
        if (worthDifference.compareTo(BigDecimal.ZERO) != 0) {
            if (worthDifference.compareTo(BigDecimal.ZERO) > 0) {
                throw exception(ORDER_SPLIT_ITEM_WORTH_MANY_EXCEPTION, worthDifference.setScale(2, RoundingMode.HALF_UP));
            } else {
                throw exception(ORDER_SPLIT_ITEM_WORTH_FEW_EXCEPTION, worthDifference.negate().setScale(2, RoundingMode.HALF_UP));
            }
        }

    }

    @Override
    public void checkWarehouseInId(List<OrderSpiltItemSpecsRecordVO> specsRecordVOList, List<OrderWarehouseInDO> warehouseInDOList) {
        // 获取订单项的全部入仓记录id
        List<Long> warehouseInIdList = warehouseInDOList.stream().filter(Objects::nonNull).map(OrderWarehouseInDO::getId).collect(Collectors.toList());
        // 获取全部的规格参数入仓记录id
        List<Long> specsRecordWarehouseInIdList = specsRecordVOList.stream().map(OrderSpiltItemSpecsRecordVO::getWarehouseInId).collect(Collectors.toList());
//        Set<Long> setSpecsRecordWarehouseInIdList = new HashSet<>(specsRecordWarehouseInIdList);
//        if (warehouseInIdList.size() != setSpecsRecordWarehouseInIdList.size()){
//            throw exception(SPILT_ORDER_WAREHOUSE_IN_REPEAT);
//        }
        if (CollectionUtil.isEmpty(specsRecordWarehouseInIdList) || specsRecordWarehouseInIdList.stream().anyMatch(Objects::isNull)) {
            // TODO 入仓记录参数中的原入仓记录id不能为空
            throw exception(WAREHOUSE_IN_RECORD_PARAM_ORG_WAREHOUSE_IN_ID_NOT_NULL);
        }
        // 判断规格记录参数中的原单入仓记录id是否有超出的
        specsRecordWarehouseInIdList.removeAll(warehouseInIdList);
        if (CollectionUtil.isNotEmpty(specsRecordWarehouseInIdList)) {
            // TODO 入仓记录中包含非法的原入仓记录id
            throw exception(WAREHOUSE_IN_RECORD_CONTAIN_ILLEGAL_ORG_WAREHOUSE_IN_ID);
        }
        // 判断入仓记录中的体积和重量值是否为null或0
        if (specsRecordVOList.stream().anyMatch(this::isNullOrZero)){
            throw exception(WAREHOUSE_IN_RECORD_DATA_NOT_IS_ZERO);
        };
    }

    private boolean isNullOrZero(OrderSpiltItemSpecsRecordVO s) {
        return Objects.isNull(s.getNum()) || s.getNum() == 0
                || Objects.isNull(s.getWeight()) || s.getWeight().compareTo(BigDecimal.ZERO) == 0
                || Objects.isNull(s.getVolume()) || s.getVolume().compareTo(BigDecimal.ZERO) == 0;
    }


    @Override
    public OrderSplitWorthDto getCheckOrderWorthDtoByOrderId(Long orderId, Long orderSplitItemId) {
        OrderDO orderDO = orderQueryService.getOrderById(orderId);
        if (orderDO == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
        // 货值需要匹配整个订单的
        BigDecimal totalWorth = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(orderDO.getCost())) {
            CostVO costVO = JSONObject.parseObject(orderDO.getCost(), CostVO.class);
            totalWorth = Objects.nonNull(costVO.getTotalWorth()) ? costVO.getTotalWorth() : BigDecimal.ZERO;
        }
        Integer sumNum = orderDO.getSumNum();
        OrderSplitWorthDto orderSplitWorthDto = splitItemMapper.getOrderAllSplitWorthDtoByOrderId(orderId, orderSplitItemId);
        if (Objects.nonNull(orderSplitWorthDto)) {
            orderSplitWorthDto.setSumNum(sumNum);
            orderSplitWorthDto.setTotalWorth(totalWorth);
            orderSplitWorthDto.setSplitResidueNum(sumNum - orderSplitWorthDto.getSplitNum());
            orderSplitWorthDto.setSplitResidueWorth(totalWorth.subtract(orderSplitWorthDto.getSplitWorth()));
        } else {
            orderSplitWorthDto = new OrderSplitWorthDto();
            orderSplitWorthDto.setSumNum(sumNum);
            orderSplitWorthDto.setTotalWorth(totalWorth);
            orderSplitWorthDto.setSplitNum(0);
            orderSplitWorthDto.setSplitWorth(BigDecimal.ZERO);
            orderSplitWorthDto.setSplitResidueNum(sumNum);
            orderSplitWorthDto.setSplitResidueWorth(totalWorth);
        }
        return orderSplitWorthDto;
    }
}
