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

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.apollo.core.event.OrderOperateLogEvent;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.order.convert.orderLocation.OrderLocationConvert;
import cn.iocoder.yudao.module.order.dal.dataobject.orderLocation.OrderLocationDO;
import cn.iocoder.yudao.module.order.dal.dataobject.orderWarehouseIn.OrderWarehouseInDO;
import cn.iocoder.yudao.module.order.dal.mysql.orderLocation.OrderLocationMapper;
import cn.iocoder.yudao.module.order.service.order.OrderItemService;
import cn.iocoder.yudao.module.order.service.order.OrderLocationService;
import cn.iocoder.yudao.module.order.service.orderWarehouseIn.OrderWarehouseInService;
import cn.iocoder.yudao.module.order.vo.orderLocation.*;
import cn.iocoder.yudao.module.order.vo.orderWarehouseIn.OrderWarehouseInQueryVO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 订单仓位 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
public class OrderLocationServiceImpl extends AbstractService<OrderLocationMapper, OrderLocationDO> implements OrderLocationService {

    @Resource
    private OrderLocationMapper orderLocationMapper;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private OrderWarehouseInService orderWarehouseInService;

    @Resource
    private ApplicationContext applicationContext;

    @Override
    public Long createOrderLocation(OrderLocationCreateReqVO createReqVO) {
        // 插入
        OrderLocationDO orderLocation = OrderLocationConvert.INSTANCE.convert(createReqVO);
        orderLocationMapper.insert(orderLocation);
        // 返回
        return orderLocation.getId();
    }

    @Override
    public void updateOrderLocation(OrderLocationUpdateReqVO updateReqVO) {
        // 校验存在
//        this.validateOrderLocationExists(updateReqVO.getId());
        // 更新
        OrderLocationDO updateObj = OrderLocationConvert.INSTANCE.convert(updateReqVO);
        orderLocationMapper.updateById(updateObj);
    }

    @Override
    public void updateWarehouseInLocation(OrderLocationUpdateReqSummaryVO orderLocationUpdateReqSummaryVO) {
        boolean update = false;

        if (orderLocationUpdateReqSummaryVO == null) {
            return;
        }

        List<OrderLocationUpdateReqVO> updateReqVOList = orderLocationUpdateReqSummaryVO.getOrderLocationUpdateReqVOList();
        if (CollectionUtil.isNotEmpty(updateReqVOList)) {
            Long warehouseInId = updateReqVOList.stream().filter(t -> t.getWarehouseInId() != null).map(OrderLocationBaseVO::getWarehouseInId).findFirst().orElse(null);
            if (warehouseInId != null) {
                List<OrderLocationDO> orderLocationDOListOld = orderLocationMapper.selectList(new LambdaQueryWrapperX<OrderLocationDO>().eq(OrderLocationDO::getWarehouseInId, warehouseInId));

                //新增
                List<OrderLocationDO> addList = updateReqVOList.stream().filter(t -> t.getId() == null).map(OrderLocationConvert.INSTANCE::convert).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(addList)) {
                    orderLocationMapper.insertBatch(addList);
                    update = true;
                }

                //修改
                List<OrderLocationDO> updateList = updateReqVOList.stream().filter(t -> orderLocationDOListOld.stream().anyMatch(l -> l.getId().equals(t.getId())))
                        .map(OrderLocationConvert.INSTANCE::convert).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(updateList)) {
                    orderLocationMapper.updateBatch(updateList);
                    update = true;
                }

                //删除
                List<OrderLocationDO> deleteList = orderLocationDOListOld.stream().filter(t -> updateReqVOList.stream().noneMatch(r -> t.getId().equals(r.getId()))).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(deleteList)) {
                    orderLocationMapper.deleteBatchIds(deleteList.stream().map(OrderLocationDO::getId).collect(Collectors.toList()));
                    update = true;
                }
            }

            //更新orderItem的入仓纪录
            Long orderId = updateReqVOList.get(0).getOrderId();
            Set<Long> orderItemIdSet = updateReqVOList.stream().map(OrderLocationBaseVO::getOrderItemId).collect(Collectors.toSet());
            orderItemService.updateOrderItemWarehouseInInfoLocation(orderId, orderItemIdSet);

            if (update) {
                applicationContext.publishEvent(new OrderOperateLogEvent(orderId, "仓库操作", "入仓记录储位修改", null));

                // //2023-04-20 更新储位后 需要更新入仓纪录对应的updateTime
                // orderWarehouseInService.update(new LambdaUpdateWrapper<OrderWarehouseInDO>()
                //         .set(OrderWarehouseInDO::getUpdater, WebFrameworkUtils.getLoginUserId() + "")
                //         .set(OrderWarehouseInDO::getUpdateTime, new Date())
                //         .eq(OrderWarehouseInDO::getId, warehouseInId));
            }
        } else {
            //当集合为空时，说明取消了所有储位
            Long orderId = orderLocationUpdateReqSummaryVO.getOrderId();
            Long orderItemId = orderLocationUpdateReqSummaryVO.getOrderItemId();

            orderLocationMapper.delete(new LambdaQueryWrapperX<OrderLocationDO>()
                    .eq(OrderLocationDO::getOrderId, orderId)
                    .eq(OrderLocationDO::getOrderItemId, orderItemId)
                    .eq(OrderLocationDO::getWarehouseInId, orderLocationUpdateReqSummaryVO.getWarehouseInId()));


            //更新orderItem的入仓纪录
            orderItemService.updateOrderItemWarehouseInInfoLocation(orderId, CollectionUtil.newHashSet(orderItemId));

            applicationContext.publishEvent(new OrderOperateLogEvent(orderId, "仓库操作", "入仓记录储位修改", null));
        }

    }

    @Override
    public void deleteOrderLocation(Long id) {
        // 校验存在
//        this.validateOrderLocationExists(id);
        // 删除
        orderLocationMapper.deleteById(id);
    }

    @Override
    public void deleteIfPresent(Long orderId,
                                Long orderItemId,
                                Long warehouseInId) {

        orderLocationMapper.delete(
                new LambdaQueryWrapperX<OrderLocationDO>().
                        eqIfPresent(OrderLocationDO::getOrderId, orderId)
                        .eqIfPresent(OrderLocationDO::getOrderItemId, orderItemId)
                        .eqIfPresent(OrderLocationDO::getWarehouseInId, warehouseInId));
    }


    @Override
    public OrderLocationDO getOrderLocation(Long id) {
        return orderLocationMapper.selectById(id);
    }

    @Override
    public List<OrderLocationDO> getOrderLocationList(Collection<Long> ids) {
        return orderLocationMapper.selectBatchIds(ids);
    }

    @Override
    public List<OrderLocationDO> getOrderLocationListByOrderId(Long orderId) {
        return orderLocationMapper.selectListWithName(orderId);
    }

    @Override
    public List<OrderLocationDO> getOrderLocationListByWarehouseInId(Long warehouseInId) {
        return orderLocationMapper.selectListWithNameByWarehouseInId(warehouseInId);
    }

    @Override
    public List<OrderLocationBackVO> getOrderLocationBackVO(Long orderId, List<OrderWarehouseInDO> filterOrderWarehouseInDOList) {
        List<OrderLocationDO> orderLocationListByOrderId = this.getOrderLocationListByOrderId(orderId);
        return this.filterByWarehouseInList(orderLocationListByOrderId, filterOrderWarehouseInDOList);
    }

    @Override
    public List<OrderLocationBackVO> filterByWarehouseInList(List<OrderLocationDO> orderLocationListByOrderId, List<OrderWarehouseInDO> filterWarehouseInIdList) {

        List<OrderLocationBackVO> orderLocationBackVOList = orderLocationListByOrderId.stream().filter(t ->
                        CollectionUtil.isNotEmpty(filterWarehouseInIdList) &&
                                filterWarehouseInIdList.stream().anyMatch(w -> w.getId().equals(t.getWarehouseInId())))
                .map(OrderLocationConvert.INSTANCE::convert).collect(Collectors.toList());
        return orderLocationBackVOList;
    }

    @Override
    public List<OrderLocationBackVO> filterByWarehouseIn(List<OrderLocationDO> orderLocationListByOrderId, OrderWarehouseInDO orderWarehouseInDO) {
        List<OrderLocationBackVO> orderLocationBackVOList = orderLocationListByOrderId.stream()
                .filter(t -> orderWarehouseInDO.getId().equals(t.getWarehouseInId()))
                .map(OrderLocationConvert.INSTANCE::convert).collect(Collectors.toList());
        return orderLocationBackVOList;
    }

    @Override
    public PageResult<OrderLocationDO> getOrderLocationPage(OrderLocationQueryVO query, PageVO page) {
        return orderLocationMapper.selectPage(page, query);
    }

    @Override
    public List<OrderLocationDO> getOrderLocationList(OrderLocationQueryVO query) {
        return orderLocationMapper.selectList(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchOrderUpdate(List<OrderLocationCreateReqVO> orderLocationCreateReqVOList) {

        if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
            // 新增新储位
            List<Long> orderIdList = orderLocationCreateReqVOList.stream()
                    .map(OrderLocationBaseVO::getOrderId)
                    .collect(Collectors.toList());

            // 首先删除，然后保存
            remove(new LambdaQueryWrapperX<OrderLocationDO>()
                    .in(OrderLocationDO::getOrderId, orderIdList)
            );

            if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
                List<OrderLocationDO> orderLocationDOList = orderLocationCreateReqVOList.stream().map(t -> OrderLocationConvert.INSTANCE.convert(t)).collect(Collectors.toList());
                saveBatch(orderLocationDOList);
            }
        }
    }

    @Override
    public void tallyUpdate(Long orderId, List<OrderLocationCreateReqVO> orderLocationCreateReqVOList) {
        if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
            //不修改储位时参数只传orderId
            orderLocationCreateReqVOList = orderLocationCreateReqVOList.stream()
                    .filter(t -> t.getWareId() != null)
                    .collect(Collectors.toList());
            //下面的逻辑会先清空储位,因此当理货未修改储位时不需要执行下面的逻辑(因为确认到仓时也会执行这个方法和理货逻辑不一样)
            if (CollectionUtil.isEmpty(orderLocationCreateReqVOList)) return;
        }

        // 储位信息 删除老储位
        deleteIfPresent(orderId, null, null);
        // 新增新储位
        if (CollectionUtil.isNotEmpty(orderLocationCreateReqVOList)) {
            //调仓到仓储位还是针对订单，但修改后要同步到所有入仓记录
            List<OrderWarehouseInDO> orderWarehouseInDOList = orderWarehouseInService.getOrderWarehouseInList(new OrderWarehouseInQueryVO().setOrderId(orderId));
            if (CollectionUtil.isNotEmpty(orderWarehouseInDOList)) {

                Long loginUserId = WebFrameworkUtils.getLoginUserId();

                for (OrderWarehouseInDO orderWarehouseInDO : orderWarehouseInDOList) {
                    List<OrderLocationDO> orderLocationDOList = orderLocationCreateReqVOList.stream().map(orderLocationCreateReqVO -> new OrderLocationDO().setOrderId(orderId)
                            .setWareId(orderLocationCreateReqVO.getWareId())
                            .setAreaId(orderLocationCreateReqVO.getAreaId())
                            .setLocationId(orderLocationCreateReqVO.getLocationId())
                            .setOrderItemId(orderWarehouseInDO.getOrderItemId())
                            .setWarehouseInId(orderWarehouseInDO.getId())
                            .setAdminId(loginUserId)).collect(Collectors.toList());

                    saveBatch(orderLocationDOList);
                }

                //更新orderItem的入仓纪录
                Set<Long> orderItemIdSet = orderWarehouseInDOList.stream().map(OrderWarehouseInDO::getOrderItemId).collect(Collectors.toSet());
                orderItemService.updateOrderItemWarehouseInInfoLocation(orderId, orderItemIdSet);
            }
        }
    }
}
