package com.hzs.sale.deliver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.SystemFieldConstants;
import com.hzs.common.core.constant.msg.SaOrderMsgConstants;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.exception.ServiceException;
import com.hzs.common.core.utils.CommonUtil;
import com.hzs.common.core.utils.StringUtils;
import com.hzs.common.domain.sale.deliver.SaDeliver;
import com.hzs.common.domain.sale.deliver.SaDeliverBarCode;
import com.hzs.common.domain.sale.deliver.SaDeliverItems;
import com.hzs.common.domain.sale.ext.SaOrderItemsExt;
import com.hzs.common.domain.sale.order.SaOrderItems;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.sale.deliver.mapper.SaDeliverBarCodeMapper;
import com.hzs.sale.deliver.mapper.SaDeliverItemsMapper;
import com.hzs.sale.deliver.mapper.SaDeliverMapper;
import com.hzs.sale.deliver.param.DeliverConfirmParam;
import com.hzs.sale.deliver.param.DeliverHandledParam;
import com.hzs.sale.deliver.param.DeliverMergeParam;
import com.hzs.sale.deliver.param.DeliverParam;
import com.hzs.sale.deliver.service.ISaDeliverService;
import com.hzs.sale.deliver.vo.DeliverHandledVO;
import com.hzs.sale.deliver.vo.DeliverPrintVO;
import com.hzs.sale.deliver.vo.DeliverVO;
import com.hzs.sale.order.mapper.SaOrderItemsMapper;
import com.hzs.system.base.IBarCodeServiceApi;
import com.hzs.system.sys.dto.LoginUser;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 销售订单-发货单 服务实现类
 */
@Service
public class SaDeliverServiceImpl extends ServiceImpl<SaDeliverMapper, SaDeliver> implements ISaDeliverService {

    @Autowired
    private SaDeliverItemsMapper saDeliverItemsMapper;
    @Autowired
    private SaDeliverBarCodeMapper saDeliverBarCodeMapper;
    @Autowired
    private SaOrderItemsMapper saOrderItemsMapper;

    @DubboReference
    IBarCodeServiceApi iBarCodeServiceApi;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean mergeDeliver(DeliverMergeParam param, List<SaOrderItemsExt> dataList, Integer pkCountry, Long userId) {
        // 收货人相同
        boolean name = param.isRecNameBool();
        // 收货电话相同
        boolean phone = param.isRecPhoneBool();
        // 收货地址相同（省、市、县）
        boolean area = param.isRecAreaBool();
        // 详细地址相同
        boolean address = param.isRecAddressBool();

        // 合单类型（0=全部合单，1=合单）
        Integer mergeType = param.getMergeType();

        // 合并发货map
        Map<String, List<SaOrderItemsExt>> orderMap = new HashMap<>();

        for (SaOrderItemsExt orderItem : dataList) {
            // 处理合并需要的key
            String key = this.handleMerge(mergeType, orderItem, name, phone, area, address);

            // 按合并规则进行整合数据
            orderMap.computeIfAbsent(key, k -> new ArrayList<>()).add(orderItem);
        }

        // 保存发货单以及发货明细
        this.saveDeliverAndItems(orderMap, userId, pkCountry);

        // 一次处理最大条数
        int pageSize = 500;
        // 3. 更新订单明细状态（本次操作订单明细数据全部更新状态）
        if (dataList.size() > 0) {
            // 一共几页
            int orderPageCount = (dataList.size() - 1) / pageSize + 1;
            for (int i = 0; i < orderPageCount; i++) {
                // 这一轮截止的下标
                int end = Math.min((i + 1) * pageSize, dataList.size());
                // 按500条每页取出数据
                List<Long> updateIdList = dataList.subList(i * pageSize, end).stream().map(SaOrderItemsExt::getPkId).collect(Collectors.toList());

                // 每500第一批进行更新操作
                saOrderItemsMapper.updateStatusBatch(updateIdList, EOrderStatus.SHIPPING.getValue(), pkCountry, userId);
            }
        }
        return true;
    }

    /**
     * 处理合并key
     *
     * @param mergeType 合单类型（0=全部合单，1=合单）
     * @param orderItem 订单明细数据
     * @param name      收货人相同
     * @param phone     收货电话相同
     * @param area      收货地址相同（省、市、县）
     * @param address   详细地址相同
     * @return
     */
    private String handleMerge(Integer mergeType, SaOrderItemsExt orderItem, boolean name, boolean phone, boolean area, boolean address) {
        // 合并发货key（默认全部合并）
        String key = "";

        if (mergeType == 0) {
            // 全部合单操作，需要每个订单单独生成发货单
            key = orderItem.getOrderCode();
        }

        // 省
        String recProvince = null != orderItem.getRecProvince() ? orderItem.getRecProvince().toString() : "";
        // 市
        String recCity = null != orderItem.getRecCity() ? orderItem.getRecCity().toString() : "";
        // 县
        String recCounty = null != orderItem.getRecCounty() ? orderItem.getRecCounty().toString() : "";
        // 详细地址
        String recAddress = StringUtils.isNotEmpty(orderItem.getRecAddress()) ? orderItem.getRecAddress() : "";


        if (name && !phone && !area && !address) {
            // 按 收货人 合单
            key = orderItem.getRecName();
        } else if (name && phone && !area && !address) {
            // 按 收货人+收货电话 合单
            key = StringUtils.join(orderItem.getRecName(), orderItem.getRecPhone());
        } else if (name && phone && area && !address) {
            // 按 收货人+收货电话+收货地址 合单
            key = StringUtils.join(orderItem.getRecName(), orderItem.getRecPhone(), recProvince, recCity, recCounty);
        } else if (name && phone && area && address) {
            // 按 收货人+收货电话+收货地址+详细地址 合单
            key = StringUtils.join(orderItem.getRecName(), orderItem.getRecPhone(), recProvince, recCity, recCounty, recAddress);
        } else if (!name && phone && !area && !address) {
            // 按 收货电话 合单
            key = orderItem.getRecPhone();
        } else if (!name && phone && area && !address) {
            // 按 收货电话+收货地址
            key = StringUtils.join(orderItem.getRecPhone(), recProvince, recCity, recCounty);
        } else if (!name && phone && area && address) {
            // 按 收货电话+收货地址+详细地址
            key = StringUtils.join(orderItem.getRecPhone(), recProvince, recCity, recCounty, recAddress);
        } else if (!name && !phone && area && !address) {
            // 按 收货地址
            key = StringUtils.join(recProvince, recCity, recCounty);
        } else if (!name && !phone && area && address) {
            // 按 收货地址+详细地址
            key = StringUtils.join(recProvince, recCity, recCounty, recAddress);
        } else if (!name && !phone && !area && address) {
            // 按 详细地址 合单
            key = StringUtils.join(recAddress);
        }
        return key;
    }


    @Override
    public List<DeliverHandledVO> queryDeliverHandledList(DeliverHandledParam param, Integer pkCountry) {
        return saDeliverItemsMapper.queryDeliverHandledList(param, pkCountry);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<DeliverPrintVO> deliverPrint(List<Long> idList, Integer pkCountry, Long userId) {
        Date date = new Date();

        // 更新打印时间
        UpdateWrapper<SaDeliver> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
        updateWrapper.in(SystemFieldConstants.PK_ID, idList);
        updateWrapper.set("PRINT_STATUS", EPrintStatus.PRINT.getValue());
        updateWrapper.set("PRINT_TIME", date);
        updateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
        updateWrapper.set(SystemFieldConstants.MODIFIED_TIME, date);
        baseMapper.update(null, updateWrapper);

        // 查询需要显示数据
        return baseMapper.deliverPrintList(idList, pkCountry);
    }

    @Override
    public SaDeliver queryDeliverByItems(Long deliverItemsId, Integer pkCountry) {
        return baseMapper.queryDeliverByItems(deliverItemsId, pkCountry);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteDeliverItems(SaDeliver saDeliver, Long deliverItemsId, Integer pkCountry, Long userId) {
        SaDeliverItems saDeliverItems = saDeliverItemsMapper.selectById(deliverItemsId);

        if (null != saDeliverItems) {
            Date nowDate = new Date();

            // 查询发货单条码
            QueryWrapper<SaDeliverBarCode> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            queryWrapper.eq("PK_DELIVER_ITEMS", deliverItemsId);
            // 发货单条码列表
            List<Integer> barCodeItemsList = saDeliverBarCodeMapper.selectList(queryWrapper).stream().map(SaDeliverBarCode::getPkBarCodeItems).collect(Collectors.toList());
            // 删除发货单条码
            UpdateWrapper<SaDeliverBarCode> deliverBarCodeUpdateWrapper = new UpdateWrapper<>();
            deliverBarCodeUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverBarCodeUpdateWrapper.eq("PK_DELIVER_ITEMS", deliverItemsId);
            deliverBarCodeUpdateWrapper.set(SystemFieldConstants.DEL_FLAG, EDelFlag.DELETE.getValue());
            deliverBarCodeUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            deliverBarCodeUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            saDeliverBarCodeMapper.update(null, deliverBarCodeUpdateWrapper);

            // 删除发货单明细
            UpdateWrapper<SaDeliverItems> deliverItemsUpdateWrapper = new UpdateWrapper<>();
            deliverItemsUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverItemsUpdateWrapper.eq(SystemFieldConstants.PK_ID, deliverItemsId);
            deliverItemsUpdateWrapper.set(SystemFieldConstants.DEL_FLAG, EDelFlag.DELETE.getValue());
            deliverItemsUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            deliverItemsUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            saDeliverItemsMapper.update(null, deliverItemsUpdateWrapper);

            // 校验删除发货单（当发货单明细全部删除时，删除发货单）
            baseMapper.deleteDeliverByItemsCount(saDeliver.getPkId(), userId, pkCountry);

            // 更新订单明细为已支付状态
            UpdateWrapper<SaOrderItems> orderItemsUpdateWrapper = new UpdateWrapper<>();
            orderItemsUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            orderItemsUpdateWrapper.eq(SystemFieldConstants.PK_ID, saDeliverItems.getPkOrderItems());
            orderItemsUpdateWrapper.set("ORDER_STATUS", EOrderStatus.PAY.getValue());
            orderItemsUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            orderItemsUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            saOrderItemsMapper.update(null, orderItemsUpdateWrapper);

            if (!CollectionUtils.isEmpty(barCodeItemsList)) {
                // 调用条码服务，解绑条码
                if (!iBarCodeServiceApi.clearBarCode(barCodeItemsList, pkCountry, userId).isSuccess()) {
                    // 重置条码失败
                    throw new ServiceException(TransactionUtils.getContent(SaOrderMsgConstants.DELIVER_CLEAR_CODE));
                }
            }
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteDeliver(List<SaDeliver> deliverList, List<Long> deliverIdList, Integer pkCountry, Long userId) {
        if (!CollectionUtils.isEmpty(deliverList)) {
            Date nowDate = new Date();

            // 查询发货单条码
            QueryWrapper<SaDeliverBarCode> deliverBarCodeQueryWrapper = new QueryWrapper<>();
            deliverBarCodeQueryWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverBarCodeQueryWrapper.in("PK_DELIVER", deliverIdList);
            // 发货单条码ID列表
            List<Integer> barCodeItemsList = saDeliverBarCodeMapper.selectList(deliverBarCodeQueryWrapper).stream().map(SaDeliverBarCode::getPkBarCodeItems).collect(Collectors.toList());
            // 删除发货单条码
            UpdateWrapper<SaDeliverBarCode> deliverBarCodeUpdateWrapper = new UpdateWrapper<>();
            deliverBarCodeUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverBarCodeUpdateWrapper.in("PK_DELIVER", deliverIdList);
            deliverBarCodeUpdateWrapper.set(SystemFieldConstants.DEL_FLAG, EDelFlag.DELETE.getValue());
            deliverBarCodeUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            deliverBarCodeUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            saDeliverBarCodeMapper.update(null, deliverBarCodeUpdateWrapper);

            // 查询发货单明细
            QueryWrapper<SaDeliverItems> deliverItemsQueryWrapper = new QueryWrapper<>();
            deliverItemsQueryWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverItemsQueryWrapper.in("PK_DELIVER", deliverIdList);
            // 订单明细ID列表
            List<Long> orderItemsList = saDeliverItemsMapper.selectList(deliverItemsQueryWrapper).stream().map(SaDeliverItems::getPkOrderItems).collect(Collectors.toList());
            // 删除发货单明细
            UpdateWrapper<SaDeliverItems> deliverItemsUpdateWrapper = new UpdateWrapper<>();
            deliverItemsUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverItemsUpdateWrapper.in("PK_DELIVER", deliverIdList);
            deliverItemsUpdateWrapper.set(SystemFieldConstants.DEL_FLAG, EDelFlag.DELETE.getValue());
            deliverItemsUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            deliverItemsUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            saDeliverItemsMapper.update(null, deliverItemsUpdateWrapper);

            // 删除发货单
            UpdateWrapper<SaDeliver> deliverUpdateWrapper = new UpdateWrapper<>();
            deliverUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            deliverUpdateWrapper.in(SystemFieldConstants.PK_ID, deliverIdList);
            deliverUpdateWrapper.set(SystemFieldConstants.DEL_FLAG, EDelFlag.DELETE.getValue());
            deliverUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            deliverUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            baseMapper.update(null, deliverUpdateWrapper);

            // 更新订单明细为已支付状态
            UpdateWrapper<SaOrderItems> orderItemsUpdateWrapper = new UpdateWrapper<>();
            orderItemsUpdateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
            orderItemsUpdateWrapper.in(SystemFieldConstants.PK_ID, orderItemsList);
            orderItemsUpdateWrapper.set("ORDER_STATUS", EOrderStatus.PAY.getValue());
            orderItemsUpdateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
            orderItemsUpdateWrapper.set(SystemFieldConstants.MODIFIED_TIME, nowDate);
            saOrderItemsMapper.update(null, orderItemsUpdateWrapper);

            if (!CollectionUtils.isEmpty(barCodeItemsList)) {
                // 调用条码服务，解绑条码
                if (!iBarCodeServiceApi.clearBarCode(barCodeItemsList, pkCountry, userId).isSuccess()) {
                    // 重置条码失败
                    throw new ServiceException(TransactionUtils.getContent(SaOrderMsgConstants.DELIVER_CLEAR_CODE));
                }
            }
        }
    }


    @Override
    public List<DeliverVO> deliverList(DeliverParam param, Integer pkCountry) {
        return baseMapper.deliverList(param, pkCountry);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean simpleDeliver(DeliverConfirmParam param, Long userId, Integer pkCountry) {
        UpdateWrapper<SaDeliver> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("LOGISTICS_CODE", param.getLogisticsCode());
        updateWrapper.set("LOGISTICS_COMPANY", param.getLogisticsCompany());
        updateWrapper.set(SystemFieldConstants.MODIFIED_TIME, new Date());
        updateWrapper.set(SystemFieldConstants.PK_MODIFIED, userId);
        updateWrapper.eq(SystemFieldConstants.PK_ID, param.getPkId());
        updateWrapper.eq(SystemFieldConstants.PK_COUNTRY, pkCountry);
        this.update(updateWrapper);

        // 更新订单明细状态
        saOrderItemsMapper.updateStatusByDeliverList(Collections.singletonList(param.getPkId()), EOrderStatus.DELIVERED.getValue(), pkCountry, userId);

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean batchDeliver(List<SaDeliver> deliverList, List<Long> deliverIdList, Long userId, Integer pkCountry, LoginUser loginUser) {
        // 更新发货单物流信息
        baseMapper.deliverBatch(deliverList, userId, pkCountry);

        // 更新订单明细状态
        saOrderItemsMapper.updateStatusByDeliverList(deliverIdList, EOrderStatus.DELIVERED.getValue(), pkCountry, userId);

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean batchDeliverNew(List<SaDeliver> deliverList, List<Long> deliverIdList, Long userId, Integer pkCountry, LoginUser loginUser) {
        // 更新发货单物流信息
        baseMapper.deliverBatchNew(deliverList, userId, pkCountry);

        // 更新订单明细状态
        saOrderItemsMapper.updateStatusByDeliverList(deliverIdList, EOrderStatus.DELIVERED.getValue(), pkCountry, userId);

        return true;
    }

    @Override
    public List<SaDeliver> queryDeliverByOrder(Long pkOrder) {
        return baseMapper.queryDeliverByOrder(pkOrder);
    }

    @Override
    public int deleteDeliverByItemsCount(Long pkDeliver, Long userId, Integer pkCountry) {
        return baseMapper.deleteDeliverByItemsCount(pkDeliver, userId, pkCountry);
    }

    /**
     * 保存发货单以及发货明细
     *
     * @param orderMap  按订单进行明细分类map
     * @param userId    用户ID
     * @param pkCountry 所属国家
     * @param <T>
     */
    private <T> void saveDeliverAndItems(Map<T, List<SaOrderItemsExt>> orderMap, Long userId, Integer pkCountry) {
        // 当前时间
        Date nowDate = new Date();

        // 遍历订单，封装发货单
        orderMap.forEach((key, orderItemsList) -> {
            // 订单发货，基础数据查询时放在明细中，此处直接取第一条数据
            SaOrderItemsExt saOrderItems = orderItemsList.get(0);

            // 发货单数据
            SaDeliver saDeliver = new SaDeliver();
            saDeliver.setDeliverCode(CommonUtil.createSerialNumber(EOrderPrefix.DELIVERY_CODE));
            saDeliver.setRecName(saOrderItems.getRecName());
            saDeliver.setRecPhone(saOrderItems.getRecPhone());
            saDeliver.setRecProvince(saOrderItems.getRecProvince());
            saDeliver.setRecCity(saOrderItems.getRecCity());
            saDeliver.setRecCounty(saOrderItems.getRecCounty());
            saDeliver.setRecAddress(saOrderItems.getRecAddress());
            saDeliver.setPkCountry(pkCountry);
            saDeliver.setPkCreator(userId);
            saDeliver.setCreationTime(nowDate);
            saDeliver.setPkModified(userId);
            saDeliver.setModifiedTime(nowDate);
            saDeliver.setTranType(saOrderItems.getTranType());

            // 1. 发货单入库
            if (this.save(saDeliver)) {
                // 发货明细列表
                List<SaDeliverItems> saDeliverItemsList = new ArrayList<>();

                for (SaOrderItemsExt orderItems : orderItemsList) {
                    // 发货单明细数据
                    SaDeliverItems saDeliverItems = new SaDeliverItems();
                    saDeliverItems.setPkDeliver(saDeliver.getPkId());
                    saDeliverItems.setPkOrder(orderItems.getPkOrder());
                    saDeliverItems.setPkOrderItems(orderItems.getPkId());
                    saDeliverItems.setPkProduct(orderItems.getPkProduct());
                    saDeliverItems.setQuantity(orderItems.getQuantity());
                    saDeliverItems.setPkWaresSpecsSku(orderItems.getPkWaresSpecsSku().intValue());
                    saDeliverItems.setPkWaresDetail(orderItems.getPkWaresDetail());
                    saDeliverItems.setSpecsName(orderItems.getSpecsName());
                    saDeliverItems.setSpecsNameId(orderItems.getSpecsNameId());
                    saDeliverItems.setPkCountry(pkCountry);
                    saDeliverItems.setPkCreator(userId);
                    saDeliverItems.setCreationTime(nowDate);
                    saDeliverItems.setPkModified(userId);
                    saDeliverItems.setModifiedTime(nowDate);
                    saDeliverItemsList.add(saDeliverItems);
                }
                // 2. 发货单明细表 入库
                saDeliverItemsMapper.insertBatch(saDeliverItemsList);
            }
        });
    }

}
