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

import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.order.dal.dataobject.orderWarehouseCheck.OrderWarehouseCheckDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderWarehouseIn.OrderWarehouseInDO;
import cn.iocoder.yudao.module.order.dal.mysql.orderWarehouseCheck.OrderWarehouseCheckMapper;
import cn.iocoder.yudao.module.order.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.order.service.order.OrderBusinessService;
import cn.iocoder.yudao.module.order.service.orderWarehouseIn.OrderWarehouseInService;
import cn.iocoder.yudao.module.order.vo.orderWarehouseCheck.OrderWarehouseCheckUpdateItemVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@Validated
public class OrderWarehouseCheckServiceImpl
        extends AbstractService<OrderWarehouseCheckMapper, OrderWarehouseCheckDO>
        implements OrderWarehouseCheckService {
    @Autowired
    private OrderBusinessService orderBusinessService;

    @Autowired
    private OrderWarehouseInService orderWarehouseInService;

    @Override
    public List<OrderWarehouseCheckDO> list(long orderId) {
        return abstractMapper.selectList(OrderWarehouseCheckDO::getOrderId, orderId);
    }

    // 到仓信息统计
    private class Sum {
        int cartons = 0; // 到仓总箱数
        int quantity = 0; // 到仓总数量
        BigDecimal volume = BigDecimal.ZERO; // 到仓总体积
        BigDecimal weight = BigDecimal.ZERO; // 到仓总重量

        // 将到仓信息累加
        void add(OrderWarehouseCheckDO checkDo) {
            cartons += checkDo.getCheckCartonsNum();
            quantity += checkDo.getCheckQuantityAll();
            volume = volume.add(checkDo.getCheckVolume());
            weight = weight.add(checkDo.getCheckWeight());
        }

        // 将统计数据更新到订单中
        void done(long orderId) {
            orderBusinessService.orderToWarehouse(orderId, cartons, quantity, volume, weight);
        }
    }

    // 重置到仓数据为入仓数据
    private void reset(OrderWarehouseCheckDO checkDo) {
        checkDo.setCheckVolume(checkDo.getVolume());
        checkDo.setCheckWeight(checkDo.getWeight());
        checkDo.setCheckCartonsNum(checkDo.getCartonsNum());
        checkDo.setCheckQuantityAll(checkDo.getQuantityAll());
    }

    @Override
    public void check(long orderId) {
        Sum sum = new Sum();

        // 全部到仓，复制入仓信息
        for (OrderWarehouseInDO inDo : orderWarehouseInService.selectList(OrderWarehouseInDO::getOrderId, orderId)) {
            OrderWarehouseCheckDO checkDo = new OrderWarehouseCheckDO();

            BeanUtils.copyProperties(inDo, checkDo);
            reset(checkDo);
            sum.add(checkDo);
            abstractMapper.insert(checkDo);
        }

        sum.done(orderId);
    }

    @Override
    public void revoke(long orderId) {
        LambdaQueryWrapper<OrderWarehouseCheckDO> wrapper = Wrappers.lambdaQuery();

        // 清空到仓信息
        abstractMapper.delete(wrapper.eq(OrderWarehouseCheckDO::getOrderId, orderId));
        orderBusinessService.revokeToWarehouse(orderId);
    }

    @Override
    public void force(long orderId) {
        Sum sum = new Sum();

        // 强制到仓信息一致
        for (OrderWarehouseCheckDO checkDo : list(orderId)) {
            reset(checkDo);
            sum.add(checkDo);
            abstractMapper.updateById(checkDo);
        }

        sum.done(orderId);
    }

    @Override
    public void update(long orderId, List<OrderWarehouseCheckUpdateItemVO> updates) {
        Sum sum = new Sum();
        Map<Long, OrderWarehouseCheckDO> mappings = list(orderId).stream()
                .collect(Collectors.toMap(OrderWarehouseCheckDO::getId, Function.identity()));
        ServiceException exception = ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_WAREHOUSE_CHECK_NOT_EXISTS);

        // 应用更新数据到到仓详情
        for (OrderWarehouseCheckUpdateItemVO update : updates) {
            OrderWarehouseCheckDO checkDo = Optional.ofNullable(mappings.get(update.getId()))
                    .orElseThrow(() -> exception);

            checkDo.setCheckVolume(update.getCheckVolume());
            checkDo.setCheckWeight(update.getCheckWeight());
            checkDo.setCheckCartonsNum(update.getCheckCartonsNum());
            checkDo.setCheckQuantityAll(update.getCheckQuantityAll());
        }

        // 统计并更新到数据库
        for (OrderWarehouseCheckDO checkDo : mappings.values()) {
            sum.add(checkDo);
            abstractMapper.updateById(checkDo);
        }

        sum.done(orderId);
    }
}
