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

import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
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.orderWarehouseIn.OrderWarehouseInDO;
import cn.iocoder.yudao.module.order.dal.mysql.order.OrderMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderItem.OrderItemMapper;
import cn.iocoder.yudao.module.order.dal.mysql.orderWarehouseIn.OrderWarehouseInMapper;
import cn.iocoder.yudao.module.order.dto.OrderBackInfoDto;
import cn.iocoder.yudao.module.order.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.order.service.order.OrderBusinessService;
import cn.iocoder.yudao.module.order.service.order.OrderQueryService;
import cn.iocoder.yudao.module.order.service.order.OrderService;
import cn.iocoder.yudao.module.order.vo.order.ApplyInfoVO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.order.vo.orderLabel.*;
import cn.iocoder.yudao.module.order.dal.dataobject.orderLabel.OrderLabelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.order.convert.orderLabel.OrderLabelConvert;
import cn.iocoder.yudao.module.order.dal.mysql.orderLabel.OrderLabelMapper;

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

/**
 * 订单箱号标签 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
public class OrderLabelServiceImpl extends AbstractService<OrderLabelMapper, OrderLabelDO> implements OrderLabelService {

    @Resource
    private OrderLabelMapper orderLabelMapper;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderService orderService;
    @Resource
    private OrderBusinessService orderBusinessService;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private OrderWarehouseInMapper orderWarehouseInMapper;

    @Override
    public void saveOrUpdateLabel(SaveOrUpdateOrderLabelDto saveOrUpdateOrderLabelDto) {

        Long orderId = saveOrUpdateOrderLabelDto.getOrderId();
        List<OrderLabelDto> orderLabelDtoList = saveOrUpdateOrderLabelDto.getOrderLabelDtoList();

        OrderDO orderDO = orderMapper.selectById(orderId);
        if (orderDO == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
        }

        List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInMapper.selectList(OrderWarehouseInDO::getOrderId, orderDO.getOrderId());
        if (CollectionUtil.isEmpty(orderWarehouseInDOList)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_IN_NOT_EXISTS);
        }

        String orderNo = orderDO.getOrderNo();
        if (CollectionUtil.isEmpty(orderLabelDtoList)) {
            orderLabelDtoList = new ArrayList<>();
        }

        List<Integer> myLabelList = new ArrayList<>();
        for (OrderLabelDto orderLabelDto : orderLabelDtoList) {
            getLabelList(myLabelList, orderLabelDto.getStart(), orderLabelDto.getEnd());
        }

        //判断本身是否有重复
        long distinctSize = myLabelList.stream().distinct().count();
        if (distinctSize != myLabelList.size()) {
            throw ServiceExceptionUtil.exception(ORDER_LABEL_OVERLAY);
        }

        //20221225 暂时去除订单的父订单关联验证
        // if (parentOrderId != null) {
        //     //通过orderId=父订单id 找到父订单的箱号（这个在拆单后再拆单有用）
        //     List<OrderLabelDO> orderWarehouseInTagDOList = orderLabelMapper.selectList(new LambdaQueryWrapperX<OrderLabelDO>().eq(OrderLabelDO::getOrderId, parentOrderId));
        //     //父标签号存在，则看箱是否存在
        //     if (CollectionUtil.isNotEmpty(orderWarehouseInTagDOList)) {
        //         List<Integer> parentLabelList = new ArrayList<>();
        //         for (OrderLabelDO orderLabelDO : orderWarehouseInTagDOList) {
        //             getLabelList(parentLabelList, orderLabelDO.getStart(), orderLabelDO.getEnd());
        //         }
        //         Integer notExisted = myLabelList.stream().filter(my -> parentLabelList.stream().noneMatch(p -> p.equals(my))).findFirst().orElse(null);
        //         if (notExisted != null) {
        //             throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_LABEL_NOT_EXISTS, orderDO.getOrderNo().split("-")[0] + "-" + notExisted);
        //         }
        //     }
        //
        //     //判断labelSet是否被父订单下的其他子订单的lableSet占用了
        //     List<OrderLabelDO> otherChildrenLabelDoList = orderLabelMapper.selectList(new LambdaQueryWrapperX<OrderLabelDO>().eq(OrderLabelDO::getParentOrderId, parentOrderId)
        //             // 排除自身（用于修改箱号）
        //             .ne(OrderLabelDO::getOrderId, orderId));
        //     if (CollectionUtil.isNotEmpty(otherChildrenLabelDoList)) {
        //
        //         List<Integer> otherChildrenLabelSet = new ArrayList<>();
        //         for (OrderLabelDO orderLabelDO : orderWarehouseInTagDOList) {
        //             getLabelList(otherChildrenLabelSet, orderLabelDO.getStart(), orderLabelDO.getEnd());
        //         }
        //
        //         Collection<Integer> intersection = CollUtil.intersection(myLabelList, otherChildrenLabelSet);
        //         if (CollectionUtil.isNotEmpty(intersection)) {
        //             List<Integer> list = intersection.stream().sorted().collect(Collectors.toList());
        //             throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_LABEL_ALREADY_BEEN_USED, orderDO.getOrderNo().split("-")[0] + "-" + list.get(0));
        //         }
        //     }
        // }

        // 若父订单没有标签号，则随意填写，但要保证的是入箱总箱数与标签箱号一致
        Integer warehouseInNum = orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getCartonsNum).reduce(0, Integer::sum);
        if (warehouseInNum != myLabelList.size()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_LABEL_NUM_NOT_SAME_WITH_WAREHOUSE_IN_NUM);
        }

        List<ApplyInfoVO> applyInfoVOList = new ArrayList<>();


        //验证通过，就保存标签
        List<OrderLabelDto> waitToSaveList = orderLabelDtoList.stream().filter(dto -> dto.getId() == null).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(waitToSaveList)) {

            //若没有老的更新，则说明需要把老的全部删除
            if (orderLabelDtoList.stream().noneMatch(dto -> dto.getId() != null)) {
                List<OrderLabelDO> orderLabelDOList = orderLabelMapper.selectList(new LambdaQueryWrapperX<OrderLabelDO>().eq(OrderLabelDO::getOrderId, orderId));
                if (CollectionUtil.isNotEmpty(orderLabelDOList)) {

                    //添加删除日志
                    String deleteNote = orderLabelDOList.stream().map(orderLabelDO -> orderLabelDO.getStart() + "~" + orderLabelDO.getEnd()).collect(Collectors.joining(","));
                    applyInfoVOList.add(new ApplyInfoVO().setName("标签箱号").setOrgValue(deleteNote));

                    orderLabelMapper.delete(new LambdaQueryWrapperX<OrderLabelDO>().eq(OrderLabelDO::getOrderId, orderId));
                }
            }

            //新增新的
            List<OrderLabelDO> tagDOList = waitToSaveList.stream().map(dto -> {
                OrderLabelDO orderLabelDO = new OrderLabelDO();
                orderLabelDO.setStart(dto.getStart());
                orderLabelDO.setEnd(dto.getEnd());
                orderLabelDO.setOrderId(orderId);
                return orderLabelDO;
            }).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(tagDOList)) {

                //添加新增日志
                String addNote = tagDOList.stream().map(orderLabelDO -> orderLabelDO.getStart() + "~" + orderLabelDO.getEnd()).collect(Collectors.joining(","));
                applyInfoVOList.add(new ApplyInfoVO().setName("标签箱号").setNewValue(addNote).setType(0));

                this.saveBatch(tagDOList);
            }
        }


        //更新标签
        List<Long> orderLabelIds = orderLabelDtoList.stream().filter(dto -> dto.getId() != null).map(OrderLabelDto::getId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(orderLabelIds)) {
            List<OrderLabelDO> orderLabelDOList = orderLabelMapper.selectBatchIds(orderLabelIds);

            if (CollectionUtil.isNotEmpty(orderLabelDOList)) {
                //更新标签
                for (OrderLabelDO orderLabelDO : orderLabelDOList) {
                    orderLabelDtoList.stream().filter(t -> orderLabelDO.getId().equals(t.getId())).findFirst().ifPresent(t -> {

                        //添加变更日志
                        if (!Objects.equals(orderLabelDO.getStart(), t.getStart()) || !Objects.equals(orderLabelDO.getEnd(), t.getEnd())) {
                            applyInfoVOList.add(new ApplyInfoVO().setName("标签箱号").setOrgValue(orderLabelDO.getStart() + "~" + orderLabelDO.getEnd()).setNewValue(t.getStart() + "~" + t.getEnd()));
                        }

                        orderLabelDO.setStart(t.getStart());
                        orderLabelDO.setEnd(t.getEnd());
                    });
                }
                orderLabelMapper.updateBatch(orderLabelDOList);
            }
        }

        //记录日志
        if (saveOrUpdateOrderLabelDto.isAddLog()) {
            orderBusinessService.addOrderOperateLog(orderId, "", "修改标签箱号", applyInfoVOList);
        }
    }

    @Override
    public Long createLabel(OrderLabelCreateReqVO createReqVO) {
        // 插入
        OrderLabelDO label = OrderLabelConvert.INSTANCE.convert(createReqVO);
        orderLabelMapper.insert(label);
        // 返回
        return label.getId();
    }

    @Override
    public void updateLabel(OrderLabelUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateLabelExists(updateReqVO.getId());
        // 更新
        OrderLabelDO updateObj = OrderLabelConvert.INSTANCE.convert(updateReqVO);
        orderLabelMapper.updateById(updateObj);
    }

    @Override
    public void deleteLabel(Long id) {
        // 校验存在
        this.validateLabelExists(id);
        // 删除
        orderLabelMapper.deleteById(id);
    }

    @Override
    public void deleteLabelByOrderId(Long orderId) {
        orderLabelMapper.delete(new LambdaQueryWrapperX<OrderLabelDO>().eq(OrderLabelDO::getOrderId, orderId));
    }

    private void validateLabelExists(Long id) {
        if (orderLabelMapper.selectById(id) == null) {
            throw exception(ORDER_LABEL_NOT_EMPTY);
        }
    }

    @Override
    public OrderLabelDO getLabel(Long id) {
        return orderLabelMapper.selectById(id);
    }

    @Override
    public List<OrderLabelDO> getLabelList(Collection<Long> ids) {
        return orderLabelMapper.selectBatchIds(ids);
    }

    @Override
    public List<OrderLabelBackVO> getLabelListByOrder(Long orderId) {
        List<OrderLabelDO> orderLabelDOList = orderLabelMapper.selectList(new LambdaQueryWrapperX<OrderLabelDO>().eq(OrderLabelDO::getOrderId, orderId));
        return OrderLabelConvert.INSTANCE.convertList(orderLabelDOList);
    }

    @Override
    public OrderLabelDto getLabelWaitInByOrder(Long orderId) {
        OrderLabelDto orderLabelDto = new OrderLabelDto();

        OrderDO orderDO = orderMapper.selectById(orderId);
        Long parentOrderId = orderDO.getParentOrderId();
        String[] orderNoAndSeq = orderDO.getOrderNo().split(StrUtil.DASHED);
        if (orderNoAndSeq.length == 2) {
            int orderSeq = Integer.parseInt(orderNoAndSeq[1]);
            if (orderSeq == 1) {
                orderLabelDto.setStart(1);

                List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapperX<OrderItemDO>().eq(OrderItemDO::getOrderId, orderId));
                int end = orderItemDOList.stream().mapToInt(OrderItemDO::getNum).sum();
                orderLabelDto.setEnd(end);
            } else {
                List<OrderDO> orderList = orderService.selectList(new LambdaQueryWrapperX<OrderDO>().eq(OrderDO::getParentOrderId, parentOrderId));
                //保存每一个orderSeq的开始和结束值
                Map<Integer, OrderLabelDto> map = new HashMap<>();
                //排序
                orderList.sort(Comparator.comparingInt(o -> Integer.parseInt(o.getOrderNo().split(StrUtil.DASHED)[1])));

                int start = 0;
                // 所有的子订单箱号不应该跳号
                for (OrderDO order : orderList) {
                    OrderLabelDto label = new OrderLabelDto();
                    label.setStart(start + 1);
                    List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapperX<OrderItemDO>().eq(OrderItemDO::getOrderId, order.getOrderId()));
                    int end = orderItemDOList.stream().mapToInt(OrderItemDO::getNum).sum();

                    label.setEnd(start + end);
                    map.put(Integer.parseInt(order.getOrderNo().split(StrUtil.DASHED)[1]), label);

                    //为下一个seq做准备
                    start = label.getEnd();
                }

                return map.get(orderSeq);
            }

        } else {
            orderLabelDto.setStart(1);

            List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapperX<OrderItemDO>().eq(OrderItemDO::getOrderId, orderId));
            int end = orderItemDOList.stream().mapToInt(OrderItemDO::getNum).sum();
            orderLabelDto.setEnd(end);
        }
        return orderLabelDto;
    }

    @Override
    public PageResult<OrderLabelDO> getLabelPage(OrderLabelQueryVO query, PageVO page) {
        return orderLabelMapper.selectPage(page, query);
    }

    @Override
    public List<OrderLabelDO> getLabelList(OrderLabelQueryVO query) {
        return orderLabelMapper.selectList(query);
    }

    @Override
    public void updateSplitOrderLabel(Long parentOrderId, List<OrderDO> childrenOrders) {
        // 获取父订单的箱号范围
        List<OrderLabelDO> orderLabelDOList = orderLabelMapper.selectList(new LambdaQueryWrapper<OrderLabelDO>().eq(OrderLabelDO::getOrderId, parentOrderId));
        Date now = new Date();
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if (CollectionUtil.isNotEmpty(orderLabelDOList)) {
            orderLabelDOList = orderLabelDOList.stream().sorted(Comparator.comparing(OrderLabelDO::getStart)).collect(Collectors.toList());
            List<Integer> labelList = new ArrayList<>();
            for (OrderLabelDO orderLabel : orderLabelDOList) {
                getLabelList(labelList, orderLabel.getStart(), orderLabel.getEnd());
            }
            labelList = labelList.stream().sorted().collect(Collectors.toList());
            //排序
            // 2023-11-18 因为这里涉及到海运与空运的拆单都存在，订单编号会变动，不再使用此订单尾标签排序
//            childrenOrders.sort(Comparator.comparingInt(o -> Integer.parseInt(o.getOrderNo().split(StrUtil.DASHED)[1])));
            int start = 0;
            int end = 0;
            for (OrderDO childrenOrder : childrenOrders) {
                if (labelList.size() < start + 1) {
                    throw exception(ORDER_LABEL_NUM_NOT_SAME_WITH_WAREHOUSE_IN_NUM);
                }
                List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapperX<OrderItemDO>().eq(OrderItemDO::getOrderId, childrenOrder.getOrderId()));
                end = end + orderItemDOList.stream().mapToInt(OrderItemDO::getNum).sum();
                for (int i = start + 1; i < end; i++) {
                    if (labelList.size() < i + 1) {
                        throw exception(ORDER_LABEL_NUM_NOT_SAME_WITH_WAREHOUSE_IN_NUM);
                    }
                    if (labelList.get(i) - labelList.get(i - 1) > 1) {
                        // 不是连续箱号，则上一个箱号就是结束箱号
                        this.saveSplitOrderLabel(labelList.get(start), labelList.get(i - 1), childrenOrder.getOrderId(), childrenOrder.getParentOrderId(), now, userId);
                        // 重置开始箱号
                        start = labelList.get(i - 1);
                    }
                }
                this.saveSplitOrderLabel(labelList.get(start), labelList.get(end - 1), childrenOrder.getOrderId(), childrenOrder.getParentOrderId(), now, userId);
                start = end;
            }
            // 删除原标签记录
            this.removeByIds(orderLabelDOList.stream().map(OrderLabelDO::getId).collect(Collectors.toList()));
        } else {
            int start = 0;
            int end = 0;
            for (OrderDO childrenOrder : childrenOrders) {
                List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapperX<OrderItemDO>().eq(OrderItemDO::getOrderId, childrenOrder.getOrderId()));
                end = end + orderItemDOList.stream().mapToInt(OrderItemDO::getNum).sum();
                this.saveSplitOrderLabel(start + 1, end, childrenOrder.getOrderId(), childrenOrder.getParentOrderId(), now, userId);
                start = end;
            }
        }
    }

    public void saveSplitOrderLabel(int start, int end, Long orderId, Long parentOrderId, Date now, Long userId) {
        OrderLabelDO labelDO = new OrderLabelDO();
        labelDO.setCreateTime(now);
        labelDO.setCreator(String.valueOf(userId));
        labelDO.setUpdateTime(now);
        labelDO.setUpdater(String.valueOf(userId));
        labelDO.setOrderId(orderId);
        labelDO.setParentOrderId(parentOrderId);
        labelDO.setStart(start);
        labelDO.setEnd(end);
        this.save(labelDO);
    }

    @Override
    public void getLabelList(List<Integer> labelList, Integer start2, Integer end2) {
        Integer start = start2;
        Integer end = end2;
        if (start.equals(end)) {
            labelList.add(start);
        } else if (end > start) {
            for (int i = start; i <= end; i++) {
                labelList.add(i);
            }
        }
    }

    @Override
    public void updateRevokeSplitOrderLabel(OrderDO orderDO, List<OrderBackInfoDto> childrenOrderList) {
        Date now = new Date();
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        // 所有子订单的订单id
        List<Long> orderIds = childrenOrderList.stream().map(OrderBackInfoDto::getOrderId).collect(Collectors.toList());
        // 获取所有子订单的箱号范围
        List<OrderLabelDO> orderLabelDOList = orderLabelMapper.selectList(new LambdaQueryWrapper<OrderLabelDO>().in(OrderLabelDO::getOrderId, orderIds));
        // 排序
//        orderLabelDOList = orderLabelDOList.stream().sorted(Comparator.comparing(OrderLabelDO::getStart)).collect(Collectors.toList());
        // 撤销拆单后根据母订单的总入仓箱数直接重新排列原母订单的箱号
        int start = 1;
        int end = orderDO.getSumNum();
//        for (OrderLabelDO labelDO : orderLabelDOList) {
//            if (start == 0) {
//                start = labelDO.getStart();
//            }
//            if ((end + 1) < labelDO.getStart()){
//                // 当箱号中间存在跳号时标签记录中断，先添加之前的,然后以当前箱号起始点重新计算新的箱号区间
//                this.saveSplitOrderLabel(start, end, orderDO.getOrderId(), null, now, userId);
//                start = labelDO.getStart();
//            }
//            end = labelDO.getEnd();
//        }
        this.saveSplitOrderLabel(start, end, orderDO.getOrderId(), null, now, userId);
        // 删除之前的子拆单箱号
        this.removeByIds(orderLabelDOList.stream().map(OrderLabelDO::getId).collect(Collectors.toList()));
    }
}
