package com.jwipc.order.logic.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.jwipc.exception.DaoException;
import com.jwipc.order.constant.MarkOrderType;
import com.jwipc.order.constant.PurchaseOrderStatus;
import com.jwipc.order.convert.PurchaseOrderMarkConvert;
import com.jwipc.order.dto.OrderPlanImportDTO;
import com.jwipc.order.dto.PurchaseOrderMarkDTO;
import com.jwipc.order.entity.PurchaseOrder;
import com.jwipc.order.entity.PurchaseOrderDetail;
import com.jwipc.order.entity.PurchaseOrderMark;
import com.jwipc.order.logic.PurchaseOrderMarkLogic;
import com.jwipc.order.service.IPurchaseOrderDetailService;
import com.jwipc.order.service.IPurchaseOrderMarkService;
import com.jwipc.order.service.IPurchaseOrderService;
import com.jwipc.security.LoginUtil;
import com.jwipc.util.DateUtils;
import com.jwipc.util.EasyExcelImportUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p> </p>
 *
 * @author BOGON
 * @version 1.0
 * @since JDK 1.8
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PurchaseOrderMarkLogicImpl implements PurchaseOrderMarkLogic {
    private final IPurchaseOrderMarkService purchaseOrderMarkService;
    private final IPurchaseOrderService purchaseOrderService;
    private final IPurchaseOrderDetailService purchaseOrderDetailService;
    private final PurchaseOrderMarkConvert purchaseOrderMarkConvert;

    @Override
    public void updateBatch(List<PurchaseOrderMarkDTO> dtos) {
        List<PurchaseOrderMark> purchaseOrderMark = purchaseOrderMarkConvert.dto2Entities(dtos);
        purchaseOrderMark.forEach(a -> {
            a.setUpdateTime(LocalDateTime.now());
            a.setUpdateUser(LoginUtil.getUserId());
        });
        final Map<Long, BigDecimal> currentIdCountMap = purchaseOrderMark.stream()
                .collect(Collectors.toMap(PurchaseOrderMark::getId, a -> a.getMarkCount()));
        final List<Long> ids = purchaseOrderMark.stream().map(PurchaseOrderMark::getId).collect(Collectors.toList());
        List<PurchaseOrderDetail> list = purchaseOrderDetailService.listByIds(ids);
        final List<Long> orderIds = list.stream().map(PurchaseOrderDetail::getOrderId).collect(Collectors.toList());
        final Map<Long, BigDecimal> dbIdCountMap = list.stream()
                .collect(Collectors.toMap(PurchaseOrderDetail::getId, a -> a.getNoClearNum()));
        for (Long id : currentIdCountMap.keySet()) {
            final BigDecimal count = currentIdCountMap.get(id);
            final BigDecimal dbCount = dbIdCountMap.get(id);
            if (dbCount.compareTo(count) < 0) {
                throw new DaoException("未清数量不够，无法修改!");
            }
        }
        purchaseOrderMarkService.saveOrUpdateBatch(purchaseOrderMark);
        //需要查询订单，然后把订单状态改成 OrderState06

        hanlderOrder(orderIds);
    }

    @Override
    public Set<String> importMark(MultipartFile file, int type) {
        Set<String> msg = Sets.newHashSet();
        try {
            List<Map<String, String>> list = EasyExcelImportUtils.parseExcelToData(file.getInputStream(), 2);
            log.info("导入数据信息:{}", list);
            final Map<Object, Long> materialSize = list.stream()
                    .collect(Collectors.groupingBy(a -> a.get("发料料号"), Collectors.counting()));
            final List<Object> collect = materialSize.keySet().stream().filter(key -> materialSize.get(key) > 1)
                    .collect(Collectors.toList());
            Set<String> duplicateCodes = Sets.newHashSet();
            collect.stream().forEach(a -> duplicateCodes.add(a.toString()));
            if (CollUtil.isNotEmpty(duplicateCodes)) {
                throw new DaoException(duplicateCodes.stream().collect(Collectors.joining(",")) + "发料料号重复了");
            }
            final Map<String, String> stringObjectMap = list.get(0);
            String pickupDate = "";
            List<String> stockDate = Lists.newArrayList();
            for (String s : stringObjectMap.keySet()) {
                if (s.indexOf("-") != -1) {
                    if (Strings.isNullOrEmpty(pickupDate)) {
                        pickupDate = s;
                    } else {
                        stockDate.add(s);
                    }

                }
            }
            if (type == 0) {
                //处理每行物料的未清数量
                msg = verificationCount(list, pickupDate);
                log.info("提货日期{}", pickupDate);
                log.info("备货日期{}", stockDate);
            } else {
                markOrder(list, pickupDate, stockDate, LoginUtil.getSupplierId());
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return msg;
    }

    private Set<String> verificationCount(List<Map<String, String>> list, String pickupDate) {
        Set<String> tipMsg = Sets.newHashSet();
        for (Map<String, String> stringObjectMap : list) {
            final String materialCode = stringObjectMap.get("发料料号").toString();
            final String factoryCode = stringObjectMap.get("工厂编号").toString();
            final BigDecimal amount = new BigDecimal(stringObjectMap.get(pickupDate).toString());
            log.info("提货料号:{}", materialCode);
            log.info("提货数量:{}", amount);
            Set<Integer> poStatus = Sets.newHashSet();
            poStatus.add(PurchaseOrderStatus.AWAITING_SUPPLIER_CONFIRMATION.getStatus());
            poStatus.add(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus());
            final List<PurchaseOrderDetail> orderDetails = purchaseOrderDetailService.findForVerCount(materialCode,
                    poStatus, factoryCode);
            final BigDecimal allNum = orderDetails.stream().map(PurchaseOrderDetail::getNoClearNum)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            if (amount.compareTo(allNum) > 0) {
                tipMsg.add(materialCode + "提货:" + amount + ",未清总数:" + allNum);
            }
        }
        return tipMsg;
    }

    private void markOrder(List<Map<String, String>> list, String pickupDate, List<String> stockDate, Long userId)
    {
        for (Map<String, String> stringObjectMap : list) {
            final String materialCode = stringObjectMap.get("发料料号").toString();
            final String factoryCode = stringObjectMap.get("工厂编号").toString();
            Set<Integer> poStatus = Sets.newHashSet();
            poStatus.add(PurchaseOrderStatus.AWAITING_SUPPLIER_CONFIRMATION.getStatus());
            poStatus.add(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus());
            final List<PurchaseOrderDetail> orderDetails = purchaseOrderDetailService.findForVerCount(materialCode,
                    poStatus, factoryCode);
            final BigDecimal allNum = orderDetails.stream().map(PurchaseOrderDetail::getNoClearNum)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            log.info("提货料号:{},未清订单总数:{}", materialCode, allNum);
            List<Long> orderIds = Lists.newArrayList();
            //直接删除工厂下的料号的计划数据
            final Set<String> materialCodes = orderDetails.stream().map(PurchaseOrderDetail::getMaterialCode)
                    .collect(Collectors.toSet());
            if (CollectionUtil.isNotEmpty(orderDetails)) {
                deleteDbMark(factoryCode, materialCodes);
            }
            orderIds.addAll(markPickOrder(pickupDate, userId, stringObjectMap, orderDetails));
            orderIds.addAll(markStockOrder(stockDate, userId, stringObjectMap, orderDetails));
            hanlderOrder(orderIds);
        }
    }

    private List<Long> markPickOrder(String pickupDate, Long userId, Map<String, String> stringObjectMap,
                                     List<PurchaseOrderDetail> orderDetails)
    {
        BigDecimal amount = new BigDecimal(stringObjectMap.get(pickupDate).toString());
        log.info("提货数量:{}", amount);
        final Iterator<PurchaseOrderDetail> iterator = orderDetails.iterator();
        List<Long> orderIds = Lists.newArrayList();
        while (iterator.hasNext()) {
            final PurchaseOrderDetail orderDetail = iterator.next();
            final BigDecimal noClearNum = orderDetail.getNoClearNum();
            final Long id = orderDetail.getId();
            if (amount.subtract(noClearNum).compareTo(BigDecimal.ZERO) > 0) {
                //表示这个数量还要继续标记
                mark(id, pickupDate, noClearNum, MarkOrderType.PICKUP, userId);
                orderIds.add(orderDetail.getOrderId());
                iterator.remove();
            } else {
                //表示标记的数量已经完成了
                mark(id, pickupDate, amount, MarkOrderType.PICKUP, userId);
                orderIds.add(orderDetail.getOrderId());
                iterator.remove();
                break;
            }
            amount = amount.subtract(noClearNum);
        }
        return orderIds;
    }

    void mark(Long id, String date, BigDecimal num, MarkOrderType markType, Long userId) {
        PurchaseOrderMark purchaseOrderMark = purchaseOrderMarkService.getById(id);
        if (Objects.isNull(purchaseOrderMark)) {
            purchaseOrderMark = new PurchaseOrderMark();
            purchaseOrderMark.setId(id);
            purchaseOrderMark.setCreateTime(LocalDateTime.now());
            purchaseOrderMark.setCreateUser(userId);
            purchaseOrderMark.setUpdateTime(LocalDateTime.now());
            purchaseOrderMark.setUpdateUser(userId);
        } else {
            purchaseOrderMark.setUpdateTime(LocalDateTime.now());
            purchaseOrderMark.setUpdateUser(userId);
        }
        purchaseOrderMark.setMarkCount(num);
        purchaseOrderMark.setMarkDate(LocalDateTimeUtil.parseDate(date, DateUtils.yyyyMMddDash));
        purchaseOrderMark.setMarkType(markType.getType());
        purchaseOrderMarkService.saveOrUpdate(purchaseOrderMark);
    }

    private List<Long> markStockOrder(List<String> stockDate, Long userId, Map<String, String> stringObjectMap,
                                      List<PurchaseOrderDetail> orderDetails)
    {
        List<Long> orderIds = Lists.newArrayList();
        for (String s : stockDate) {
            BigDecimal amount = new BigDecimal(stringObjectMap.get(s).toString());
            log.info("备货数量:{}", amount);
            final Iterator<PurchaseOrderDetail> iterator = orderDetails.iterator();
            while (iterator.hasNext()) {
                final PurchaseOrderDetail orderDetail = iterator.next();
                final BigDecimal noClearNum = orderDetail.getNoClearNum();
                final Long id = orderDetail.getId();
                if (amount.subtract(noClearNum).compareTo(BigDecimal.ZERO) > 0) {
                    //表示这个数量还要继续标记
                    mark(id, s, noClearNum, MarkOrderType.STOCK, userId);
                    orderIds.add(orderDetail.getOrderId());
                    iterator.remove();
                } else {
                    //表示标记的数量已经完成了
                    mark(id, s, amount, MarkOrderType.STOCK, userId);
                    orderIds.add(orderDetail.getOrderId());
                    iterator.remove();
                    break;
                }
                amount = amount.subtract(noClearNum);
            }
        }
        return orderIds;
    }

    private void deleteDbMark(String factoryCode, Set<String> materialCodes) {
        final List<PurchaseOrderDetail> list = purchaseOrderDetailService.list(
                new LambdaQueryWrapper<PurchaseOrderDetail>().eq(PurchaseOrderDetail::getFactoryCode, factoryCode)
                        .in(PurchaseOrderDetail::getMaterialCode, materialCodes));
        final List<Long> removeIds = list.stream().map(PurchaseOrderDetail::getId).collect(Collectors.toList());
        purchaseOrderMarkService.removeBatchByIds(removeIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Set<String> importMark1(MultipartFile file) {
        Set<String> msg = Sets.newHashSet();
        try {
            List<Map<String, String>> dataList = EasyExcelImportUtils.parseExcelToData(file.getInputStream(), 2);
            List<OrderPlanImportDTO> list = Lists.newArrayList();
            for (Map<String, String> stringStringMap : dataList) {
                list.add(BeanUtil.mapToBean(stringStringMap, OrderPlanImportDTO.class, false));
            }
            log.info("导入数据信息:{}", list);
            //需要做校验判断未清数量是否符合
            List<PurchaseOrderMark> insertOrUpdateLists = Lists.newArrayList();
            List<Long> orderIds = Lists.newArrayList();
            for (OrderPlanImportDTO purchaseOrderDetailDto : list) {
                final String orderCode = purchaseOrderDetailDto.getOrderCode();
                final String orderRow = purchaseOrderDetailDto.getOrderRow();
                final String s = "SAP单号:" + orderCode + ",行号" + orderRow;
                if (Strings.isNullOrEmpty(purchaseOrderDetailDto.getMarkType())) {
                    continue;
                }
                //提货_1", "备货_2
                if (!purchaseOrderDetailDto.getMarkType().equals("提货") &&
                        !purchaseOrderDetailDto.getMarkType().equals("备货")) {
                    throw new DaoException(s + "计划类型错误，只能是 提货 或者 备货!");
                }
                if (Objects.isNull(purchaseOrderDetailDto.getMarkDate())) {
                    throw new DaoException(s + "计划日期未填写!");
                }
                if (Objects.isNull(purchaseOrderDetailDto.getMarkCount())) {
                    throw new DaoException(s + "计划数量未填写!");
                }
                Set<Integer> poStatus = Sets.newHashSet();
                poStatus.add(PurchaseOrderStatus.AWAITING_SUPPLIER_CONFIRMATION.getStatus());
                poStatus.add(PurchaseOrderStatus.CONFIRMATION_COMPLETED.getStatus());
                //需要增加订单状态判断
                final PurchaseOrderDetail purchaseOrderDetail = purchaseOrderDetailService.findForMark(poStatus,
                        orderCode, orderRow);
                if (Objects.isNull(purchaseOrderDetail)) {
                    throw new DaoException(s + "订单状态不是[待供应商确认,确认完成]或是退货订单或订单不存在!");
                }
                final BigDecimal noClearNum = purchaseOrderDetail.getNoClearNum();
                final BigDecimal markCount = purchaseOrderDetailDto.getMarkCount();
                if (markCount.compareTo(noClearNum) > 0) {
                    throw new DaoException(s + "未清数量不够，无法修改!");
                }
                PurchaseOrderMark mark = new PurchaseOrderMark();
                mark.setMarkCount(markCount);
                final String markType = purchaseOrderDetailDto.getMarkType().trim();
                mark.setId(purchaseOrderDetail.getId());
                mark.setMarkType(markType.equals("提货") ? 1 : 2);
                mark.setMarkDate(purchaseOrderDetailDto.getMarkDate());
                mark.setMarkCount(markCount);
                mark.setUpdateUser(LoginUtil.getUserId());
                mark.setUpdateTime(LocalDateTime.now());
                insertOrUpdateLists.add(mark);
                orderIds.add(purchaseOrderDetail.getOrderId());
            }
            if (CollectionUtil.isNotEmpty(insertOrUpdateLists)) {
                purchaseOrderMarkService.saveOrUpdateBatch(insertOrUpdateLists, 300);
            }
            hanlderOrder(orderIds);
        } catch (Exception e) {
            e.printStackTrace();
            if (e instanceof DaoException) {
                throw new DaoException(e.getMessage());
            } else {
                throw new DaoException("日期格式请按照2023/09/01、数量格式禁止输入文字");
            }
        }
        return msg;
    }

    private void hanlderOrder(List<Long> orderIds) {
        List<PurchaseOrder> updateLists = Lists.newArrayList();
        for (Long orderId : orderIds) {
            PurchaseOrder purchaseOrder = new PurchaseOrder();
            purchaseOrder.setId(orderId);
            purchaseOrder.setState(PurchaseOrderStatus.AWAITING_SUPPLIER_CONFIRMATION.getStatus());
            updateLists.add(purchaseOrder);
        }
        if (CollectionUtil.isNotEmpty(updateLists)) {
            purchaseOrderService.updateBatchById(updateLists);
        }
    }
}