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

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.apollo.core.event.QueryChannelInfoEvent;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.order.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderException.OrderExceptionDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderItem.OrderItemDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderTime.OrderTimeDO;
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.orderTime.OrderTimeMapper;
import cn.iocoder.yudao.module.order.enums.OrderAirTimeEnum;
import cn.iocoder.yudao.module.order.enums.OrderExceptionEnum;
import cn.iocoder.yudao.module.order.enums.OrderStatusEnum;
import cn.iocoder.yudao.module.order.enums.TransportTypeShortEnum;
import cn.iocoder.yudao.module.order.service.order.OrderAirService;
import cn.iocoder.yudao.module.order.service.order.OrderBusinessService;
import cn.iocoder.yudao.module.order.service.order.OrderService;
import cn.iocoder.yudao.module.order.service.orderException.OrderExceptionService;
import cn.iocoder.yudao.module.order.service.orderWarehousePicture.OrderWarehousePictureService;
import cn.iocoder.yudao.module.order.vo.order.OrderManualExceptionBatchReqVO;
import cn.iocoder.yudao.module.order.vo.order.WarehouseInInfoVO;
import cn.iocoder.yudao.module.order.vo.orderException.OrderExceptionCreateReqVO;
import cn.iocoder.yudao.module.order.vo.orderException.OrderExceptionDescVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;

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

/**
 * 空运订单相关业务 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
@AllArgsConstructor
@Slf4j
public class OrderAirServiceImpl extends AbstractService<OrderMapper, OrderDO> implements OrderAirService {

    private final OrderService orderService;
    private final OrderBusinessService orderBusinessService;
    private final OrderItemMapper orderItemMapper;
    private final OrderTimeMapper orderTimeMapper;
    private final OrderWarehousePictureService orderWarehousePictureService;
    private final OrderExceptionService orderExceptionService;

    @Override
    public void can(Long orderId) {
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO.getStatus() == 5 && StringUtils.isNotBlank(orderDO.getContainerNumber())){
            throw exception(ORDER_IS_PRE_INSTALLED);
        }
        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_NOT_WAREHOUSE_IN);
        }
        if (orderDO.getAbnormalState() != 0 || orderDO.getAuditType() != 0) {
            throw exception(ORDER_EXCEPTION_OR_PROCESSING_ERROR);
        }
        orderService.airCan(orderId);
    }

    @Override
    public void readyStock(Long orderId) {
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO.getStatus() == 5 && StringUtils.isNotBlank(orderDO.getContainerNumber())){
            throw exception(ORDER_IS_PRE_INSTALLED);
        }
        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_NOT_WAREHOUSE_IN);
        }
        // if (orderDO.getAbnormalState() != 0 || orderDO.getAuditType() != 0) {
        //     throw exception(ORDER_EXCEPTION_OR_PROCESSING_ERROR);
        // }
        if (orderDO.getAuditType() != 0) {
            throw exception(ORDER_HAS_PROCESSING_APPROVAL, orderDO.getOrderNo());
        }
        LambdaUpdateWrapper<OrderDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<OrderDO>().set(OrderDO::getAirShipment, 4);
        if (orderDO.getFirstStockedTime() == null) {
            lambdaUpdateWrapper.set(OrderDO::getFirstStockedTime, new Date());
        }
        lambdaUpdateWrapper.eq(OrderDO::getOrderId, orderId);
        orderService.update(null, lambdaUpdateWrapper);
        // 添加打包完成的动态，只添加一次即可
        // 判断此订单是否有入仓动态，此处操作的完成入仓，只添加一次
        long count = orderTimeMapper.selectCount(new LambdaQueryWrapper<OrderTimeDO>()
                .eq(OrderTimeDO::getOrderId, orderId)
                .eq(OrderTimeDO::getStatus, OrderAirTimeEnum.AIR_PACKED.getValue()));
        if (count == 0) {
            orderBusinessService.addAirOrderTimeLog(orderDO, OrderAirTimeEnum.AIR_PACKED, null, null, null, null, null, null);
        }
    }

    @Override
    public void readyStockProcessing(Long orderId) {
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO.getStatus() == 5 && StringUtils.isNotBlank(orderDO.getContainerNumber())){
            throw exception(ORDER_IS_PRE_INSTALLED);
        }
        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_NOT_WAREHOUSE_IN);
        }
        // if (orderDO.getAbnormalState() != 0 || orderDO.getAuditType() != 0) {
        //     throw exception(ORDER_EXCEPTION_OR_PROCESSING_ERROR);
        // }
        if (orderDO.getAuditType() != 0) {
            throw exception(ORDER_HAS_PROCESSING_APPROVAL, orderDO.getOrderNo());
        }
        orderService.update(new LambdaUpdateWrapper<OrderDO>().set(OrderDO::getAirShipment, 3).eq(OrderDO::getOrderId, orderId));
    }

    @Override
    public void canByOrderIds(Collection<Long> orderIds) {
        List<OrderDO> orderDOList = orderService.listByIds(orderIds);
        for (OrderDO orderDO : orderDOList) {
            if (orderDO.getStatus() == 5 && StringUtils.isNotBlank(orderDO.getContainerNumber())){
                throw exception(ORDER_IS_PRE_INSTALLED);
            }
            if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
                throw exception(ORDER_NOT_WAREHOUSE_IN);
            }
            if (orderDO.getAbnormalState() != 0 || orderDO.getAuditType() != 0) {
                throw exception(ORDER_EXCEPTION_OR_PROCESSING_ERROR);
            }
            orderService.airCan(orderDO.getOrderId());
        }
//        orderService.update(new LambdaUpdateWrapper<OrderDO>().set(OrderDO::getAirShipment, 2).in(OrderDO::getOrderId, orderIds));
    }

    @Override
    public void manualExceptionBatch(OrderManualExceptionBatchReqVO orderManualExceptionBatchReqVO) {

        List<Long> orderIds = orderManualExceptionBatchReqVO.getOrderIds();
        String manualExceptionType = orderManualExceptionBatchReqVO.getManualExceptionType();
        List<String> exceptionUrls = orderManualExceptionBatchReqVO.getExceptionUrls();

        for (Long orderId : orderIds) {

            OrderDO orderDO = orderService.getById(orderId);

            // 异常影像
            orderWarehousePictureService.createWarehousePictureBatch(exceptionUrls, 4, orderId);

            // 异常
            String descZh = getDesc(orderManualExceptionBatchReqVO.getDescZh(), orderManualExceptionBatchReqVO.getDescEn(), manualExceptionType, 0);
            String descEn = getDesc(orderManualExceptionBatchReqVO.getDescZh(), orderManualExceptionBatchReqVO.getDescEn(), manualExceptionType, 1);

            OrderExceptionCreateReqVO orderExceptionCreateReqVO = new OrderExceptionCreateReqVO();
            orderExceptionCreateReqVO.setOrderId(orderId);
            orderExceptionCreateReqVO.setOrderNumber(orderDO.getOrderNo());
            orderExceptionCreateReqVO.setOrderExceptionType(OrderExceptionEnum.ORDER_OTHER_EXCEPTION.getKey());
            if (CollectionUtil.isNotEmpty(exceptionUrls)) {
                orderExceptionCreateReqVO.setOrderExceptionAttr(CollectionUtil.join(exceptionUrls, ","));
            }

            orderExceptionCreateReqVO.setOrderExceptionDescVO(OrderExceptionDescVO.builder().descZh(descZh).descEn(descEn).build());

            orderExceptionService.createOrderException(orderExceptionCreateReqVO);
        }

    }


    @Override
    public void notCan(Long orderId) {
        OrderDO orderDO = orderService.getById(orderId);
        if (orderDO.getStatus() == 5 && StringUtils.isNotBlank(orderDO.getContainerNumber())){
            throw exception(ORDER_IS_PRE_INSTALLED);
        }
        if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
            throw exception(ORDER_NOT_WAREHOUSE_IN);
        }
        if (orderDO.getAbnormalState() != 0 || orderDO.getAuditType() != 0) {
            throw exception(ORDER_EXCEPTION_OR_PROCESSING_ERROR);
        }
        if (orderDO.getAirShipment() < 2) {
            throw exception(ORDER_IS_WAITING_SHIPMENT);
        }
        orderService.airNotCan(orderId);
    }

    @Override
    public void notCanByOrderIds(List<Long> orderIds) {
        List<OrderDO> orderDOList = orderService.listByIds(orderIds);
        for (OrderDO orderDO : orderDOList) {
            if (orderDO.getStatus() == 5 && StringUtils.isNotBlank(orderDO.getContainerNumber())){
                throw exception(ORDER_IS_PRE_INSTALLED);
            }
            if (orderDO.getStatus() != 5 && orderDO.getInWarehouseState() != 202) {
                throw exception(ORDER_NOT_WAREHOUSE_IN);
            }
            if (orderDO.getAbnormalState() != 0 || orderDO.getAuditType() != 0) {
                throw exception(ORDER_EXCEPTION_OR_PROCESSING_ERROR);
            }
            if (orderDO.getAirShipment() < 2) {
                throw exception(ORDER_IS_WAITING_SHIPMENT);
            }
            orderService.airNotCan(orderDO.getOrderId());
        }
    }


    @Override
    public void inspectWarehouseInOrderChannelNoCan(QueryChannelInfoEvent event) {
        // 获取已入仓的渠道相关空运订单
        List<OrderDO> orderDOList = orderService.selectList(
                new LambdaQueryWrapper<OrderDO>()
                .eq(OrderDO::getStatus, OrderStatusEnum.IN_WAREHOUSE.getValue())
                .eq(OrderDO::getTransportId, TransportTypeShortEnum.AIR_FREIGHT_LINE.getValue())
                .eq(OrderDO::getChannelId, event.getChannelId()));
        if (CollectionUtil.isNotEmpty(orderDOList)) {
            for (OrderDO orderDO : orderDOList) {
                // 检查订单的不可出特性渠道异常情况，如果有则判断是否自动处理，如果没有则判断是否生成
                // 更新完订单所有计价信息后，对未报价的订单项去生成未报价异常(待确认商品不予生成未报价异常)
                // 只对非拆单子订单进行校验
                if (Objects.isNull(orderDO.getParentOrderId()) ||
                        orderDO.getParentOrderId() == 0 ||
                        orderDO.getSplitSeparateOrder()) {

                    orderBusinessService.addOrderOperateLog(orderDO.getOrderId(), "订单操作", "渠道特性修改自动检查订单不可出渠道特性", "");
                    List<OrderItemDO> orderItemDOList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>().eq(OrderItemDO::getOrderId, orderDO.getOrderId()));
                    // 查询待处理的不可出渠道异常
                    List<OrderExceptionDO> orderNoCanShipmentChannelExceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(), null, OrderExceptionEnum.NOT_SHIPPING_CHANNEL_EXCEPTION.getKey());
                    orderDO.setIsAutomaticHandleNoCanShipmentChannelException(false);
                    // 拆单子订单如果被标记为独立订单，则与非拆单订单一样的处理逻辑
                    for (OrderItemDO orderItemDO : orderItemDOList) {
                        WarehouseInInfoVO warehouseInInfoVO = orderItemDO.getWarehouseInInfoVO();
                        // 获取订单待处理的未报价异常
                        List<OrderExceptionDO> orderNoQuoteExceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(), orderItemDO.getOrderItemId(), OrderExceptionEnum.ORDER_NO_QUOTE_EXCEPTION.getKey());
                        // 获取订单待处理的清关费未报价异常
                        List<OrderExceptionDO> orderClearanceFeeNoQuoteExceptionDOList = orderExceptionService.getPendingOrderExceptionByOrderIdAndOrderItemIdAndExceptionKey(orderDO.getOrderId(), orderItemDO.getOrderItemId(), OrderExceptionEnum.CUSTOMS_FEE_NOT_QUOTE_EXCEPTION.getKey());
                        // 已入仓订单，当没有未报价异常(包括未报价清关费异常)时才判断是否需要生成不可出渠道异常和单询异常
                        if (CollectionUtil.isEmpty(orderNoQuoteExceptionDOList) && CollectionUtil.isEmpty(orderClearanceFeeNoQuoteExceptionDOList)) {
                            // 非拆单订单检查已入仓的品名， 不可出渠道异常
                            orderBusinessService.createNoCanShipmentChannelException(orderDO, event, orderItemDO, warehouseInInfoVO, null, orderNoCanShipmentChannelExceptionDOList);
                        }
                    }
                    if (orderDO.getIsAutomaticHandleNoCanShipmentChannelException()) {
                        // 补充判断异常不为空,但是处理中状态时,不需要执行删除业务
                        if (CollectionUtil.isNotEmpty(orderNoCanShipmentChannelExceptionDOList)) {
                            for (OrderExceptionDO orderExceptionDO : orderNoCanShipmentChannelExceptionDOList) {
                                // 特性被修改后删除此异常
                                if (orderExceptionDO.getOrderExceptionStatus() == 0) {
                                    orderExceptionService.handlerRemoveNotShippingChannelExceptionById(orderExceptionDO.getId());
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private String getDesc(String descZh, String descEn, String manualExceptionType, Integer lang) {
        StringBuffer stringBuffer = new StringBuffer();
        for (String value : manualExceptionType.split(",")) {
            DictDataRespDTO data = DictFrameworkUtils.getDictDataFromCache("manual_exception_type", value);
            if (data != null) {
                if (StringUtils.isNotEmpty(stringBuffer)) {
                    stringBuffer.append(",");
                }
                stringBuffer.append(lang == 0 ? data.getLabel() : data.getLabelEn());
            }
        }

        if (lang == 0 && StringUtils.isNotEmpty(descZh)) {
            stringBuffer.append(": ").append(descZh);
        }
        if (lang == 1 && StringUtils.isNotEmpty(descEn)) {
            stringBuffer.append(": ").append(descEn);
        }

        return stringBuffer.toString();
    }
}
