package com.jwipc.order.api.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jwipc.api.constant.RestCode;
import com.jwipc.api.dto.ApiResult;
import com.jwipc.log.annotation.ApiOperateLog;
import com.jwipc.log.constant.ApiDirection;
import com.jwipc.log.constant.ThirdSysType;
import com.jwipc.order.api.convert.CreateShortagePlanConvert;
import com.jwipc.order.api.dto.CreateShortagePlanDTO;
import com.jwipc.order.api.logic.CreateShortagePlanLogic;
import com.jwipc.order.constant.ShortageDataType;
import com.jwipc.order.constant.ShortagePlanStatus;
import com.jwipc.order.convert.ShortageDetailConvert;
import com.jwipc.order.entity.ShortageData;
import com.jwipc.order.entity.ShortageDetail;
import com.jwipc.order.entity.ShortagePlan;
import com.jwipc.order.service.*;
import com.jwipc.supplier.client.QuotaManagementClient;
import com.jwipc.sys.client.DictClient;
import com.jwipc.sys.client.FactoryClient;
import com.jwipc.sys.client.ProductClient;
import com.jwipc.sys.client.PurchaseGroupClient;
import com.jwipc.sys.client.dto.DictDTO;
import com.jwipc.sys.client.dto.FactoryDTO;
import com.jwipc.sys.client.dto.ProductInfoDTO;
import com.jwipc.sys.client.dto.PurchaseGroupDTO;
import com.jwipc.util.DateUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.baomidou.dynamic.datasource.support.DdConstants.SLAVE;


/**
 * <p> </p>
 *
 * @author BOGON
 * @version 1.0
 * @since JDK 1.8
 */
@Service
@RequiredArgsConstructor
public class CreateShortagePlanLogicImpl implements CreateShortagePlanLogic {
    private final IShortagePlanService shortagePlanService;
    private final ProductClient productClient;
    private final IShortageDataService shortageDataService;
    private final PurchaseGroupClient purchaseGroupClient;
    private final FactoryClient factoryClient;
    private final CreateShortagePlanConvert createShortagePlanConvert;
    private final QuotaManagementClient quotaManagementClient;
    private final ShortageDetailConvert shortageDetailConvert;
    private final IShortageDetailService shortageDetailService;
    private final IPurchaseOrderDetailService purchaseOrderDetailService;
    private final DictClient dictClient;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ApiOperateLog(code = "createShortagePlan", name = "SAP欠料数据推送", direction = ApiDirection.OTHER_TO_SRM,
            thirdSysType = ThirdSysType.SAP)
    @DS(SLAVE)
    public ApiResult createShortagePlan(CreateShortagePlanDTO createBasicPlanDTO) {
        final ShortagePlan plan = new ShortagePlan();

//        final String newSerialNumber = shortagePlanService.findNewSerialNumber(null);
//        plan.setSerialNumber(shortagePlanLogic.genSerialNumber(DateTime.now(), newSerialNumber));

        Map<String, ProductInfoDTO> productInfoCache = Maps.newHashMap();
        final List<CreateShortagePlanDTO.ITData> itData = createBasicPlanDTO.getIT_DATA();
        final CreateShortagePlanDTO.Auth auth = createBasicPlanDTO.getIS_REQ();
        //工厂数据缓存
        final List<FactoryDTO> all = factoryClient.getAll();
        final Map<String, FactoryDTO> factoryCache = all.stream()
                .collect(Collectors.toMap(FactoryDTO::getFactory, a -> a));
        final Set<String> factoryCodes = factoryCache.keySet();
        //采购组缓存
        List<PurchaseGroupDTO> purchaseGroupDTOList = purchaseGroupClient.getAll();
        final Map<String, PurchaseGroupDTO> purchaseGroupDTOMapCache = purchaseGroupDTOList.stream()
                .collect(Collectors.toMap(PurchaseGroupDTO::getPurchaseGroupCode, a -> a));
        final Set<String> purchaseGroupCodes = purchaseGroupDTOMapCache.keySet();

        //在途供应商缓存
        final Map<String, String> deliveryOrderSupplierCodeCache = Maps.newHashMap();
        //配额最高供应商缓存map
        final Map<String, String> quoteSupplierCodeCache = Maps.newHashMap();

        List<ShortageData> shortageDataInsertLists = Lists.newArrayList();
        List<ShortageDetail> shortageDetailInsertLists = Lists.newArrayList();

        //批次号
        String dateNumber = "";
        final LocalDateTime now = LocalDateTime.now();
        //设置物料计划版本号
        if (CollUtil.isNotEmpty(itData)) {
            CreateShortagePlanDTO.ITData itDatum = itData.get(0);
            //根据版本号查询计划是否已经存在
            ShortagePlan shortagePlan = shortagePlanService.getOne(
                    new LambdaQueryWrapper<ShortagePlan>().eq(ShortagePlan::getDateNumber, itDatum.DATE_NUMBER==null?itDatum.Z_VER:itDatum.DATE_NUMBER));
            if (!Objects.isNull(shortagePlan) && shortagePlan.getId() > 0) {
                plan.setId(shortagePlan.getId());
                plan.setStatus(ShortagePlanStatus.NEW.getCode());
                if (Objects.nonNull(auth) && StringUtils.isNotEmpty(auth.NOTE1) && "X".equals(auth.NOTE1)) {
                    plan.setSynStatus("接收完成");
                }
                dateNumber = shortagePlan.getDateNumber();
            } else {
                final long maxVersion = shortagePlanService.findMaxVersion();
                final long nextVersion = maxVersion + 1;
                plan.setSerialNumber(itDatum.Z_VER);
                plan.setDateNumber(itDatum.DATE_NUMBER==null?itDatum.Z_VER:itDatum.DATE_NUMBER);
                plan.setVersion(nextVersion);
                plan.setStatus(ShortagePlanStatus.NEW.getCode());
                plan.setTitle("SAP推送");
                final LocalDate startDate = now.withDayOfMonth(1).toLocalDate();
                plan.setStartTime(startDate);
                plan.setEndTime(startDate.plusDays(60));
                plan.setCreateTime(now);
                plan.setCreateId(1L);
                dateNumber = plan.getDateNumber();
                if (Objects.nonNull(auth) && StringUtils.isNotEmpty(auth.NOTE1) && "X".equals(auth.NOTE1)) {
                    plan.setSynStatus("接收完成");
                }
            }
            shortagePlanService.saveOrUpdate(plan);
        } else {
            return ApiResult.builder().message("没有要同步的欠料计划")
                    .code(RestCode.SAP_ERROR.getCode()).build();
        }

        final Long planId = plan.getId();
        //通过缓存版本号来控制是否为第一次推送
        for (CreateShortagePlanDTO.ITData itDatum : itData) {
            final String matnr = itDatum.ZMATNR;
            final String werks = itDatum.WERKS;
            final String ekgrp = itDatum.EKGRP;
            //工厂校验
            if (!factoryCodes.contains(werks)) {
                //删除已经同步的欠料数据当前版本的。
                rebackShortAgeDataAndDetail(dateNumber,plan);
                return ApiResult.builder().message(StrUtil.format("{},工厂不存在!", werks))
                        .code(RestCode.SAP_ERROR.getCode()).build();
            }
            //采购组校验
//            if (!purchaseGroupCodes.contains(ekgrp)) {
//                //删除已经同步的欠料数据当前版本的。
//                rebackShortAgeDataAndDetail(dateNumber);
//                return ApiResult.builder().message(StrUtil.format("{},采购组编码不存在!", ekgrp))
//                        .code(RestCode.SAP_ERROR.getCode()).build();
//            }
//            final PurchaseGroupDTO purchaseGroupDTO = purchaseGroupClient.getByCode(ekgrp);
//            if (Objects.isNull(purchaseGroupDTO)) {
//                return ApiResult.builder().message(StrUtil.format("{},采购组编码不存在!", ekgrp))
//                        .code(RestCode.SAP_ERROR.getCode()).build();
//            }
            final String key = StrUtil.format("{}-{}", matnr, werks);
            ProductInfoDTO productInfoDTO = productInfoCache.get(key);
            if (Objects.isNull(productInfoDTO)) {
                final ProductInfoDTO byMaterialCodeAndFactoryCode = productClient.getByMaterialCodeAndFactoryCode(matnr,
                        werks);
                if (Objects.isNull(byMaterialCodeAndFactoryCode)) {
                    //删除已经同步的欠料数据当前版本的。
                    rebackShortAgeDataAndDetail(dateNumber,plan);
                    return ApiResult.builder().message(StrUtil.format("{},物料不存在!", matnr))
                            .code(RestCode.SAP_ERROR.getCode()).build();
                }
                productInfoCache.put(key, byMaterialCodeAndFactoryCode);
            }

            ShortageDetail shortageDetail;
            shortageDetail = createShortagePlanConvert.convert1(itDatum);
            Long id = IdWorker.getId();
            shortageDetail.setId(id);
            shortageDetail.setPlanId(planId);
            shortageDetail.setCreateTime(now);

            //这个地方需要找送货单中最新的一个的供应商信息
            //取在途供应商，先取在途订单（“交货已完成”为“否”，并且未清数量不为0）供应商 邓京术 2025-03-17
            //先检查缓存是否有该供应商
            String deliveryOrderSupplierCode = deliveryOrderSupplierCodeCache.get(key);
            if (StringUtils.isEmpty(deliveryOrderSupplierCode)) {
                deliveryOrderSupplierCode = purchaseOrderDetailService.getNewestForShortagePlan(matnr,werks);
            }

            if(StrUtil.isNotEmpty(deliveryOrderSupplierCode)) {
                deliveryOrderSupplierCodeCache.put(key, deliveryOrderSupplierCode);
                ShortageData shortageData = new ShortageData();
                shortageDetailConvert.fillData(shortageData, shortageDetail);
                shortageData.setId(null);
                shortageData.setPlanId(planId);
                shortageData.setDetailId(id);
                shortageData.setSupplierCode(deliveryOrderSupplierCode);
                shortageData.setType(ShortageDataType.MANUAL.getCode());
                shortageData.setQuota(new BigDecimal("100"));
                final BigDecimal shortageQuantity = shortageData.getShortageQuantity();
                shortageData.setShortageQuantity(shortageQuantity);
                shortageData.setRemark(itDatum.ZTEXT);
                shortageData.setMainMaterialReply(itDatum.ZBZ2);
                shortageData.setMainMaterialReplyDate(StringUtils.isNotEmpty(itDatum.EINDT)? DateUtils.formatYYYYMMDD(itDatum.EINDT):null);
                shortageDataInsertLists.add(shortageData);
            } else {
                //根据物料和工厂查 配额最高的供应商，如果相等或未分配，取随便一个 2025-03-17 邓京术
                String supplierCode = quoteSupplierCodeCache.get(key);
                if (StringUtils.isEmpty(supplierCode)) {
                    supplierCode = quotaManagementClient.getByMaterialCodeAndFactoryCodeMaxQuote(
                            matnr, werks);
                }

                if (StringUtils.isNotEmpty(supplierCode)) {
                    quoteSupplierCodeCache.put(key, supplierCode);
//                    for (QuotaManagementClientDTO quotaManagementClientDTO : quotaManagementClientDTOS) {
//                        final String supplierCode = quotaManagementClientDTO.getSupplierCode();
//                        final BigDecimal quota = quotaManagementClientDTO.getQuota();
                        ShortageData shortageData = new ShortageData();
                        shortageDetailConvert.fillData(shortageData, shortageDetail);
                        shortageData.setId(null);
                        shortageData.setPlanId(planId);
                        shortageData.setDetailId(id);
                        shortageData.setSupplierCode(supplierCode);
                        shortageData.setType(ShortageDataType.QUOTA.getCode());
                        shortageData.setQuota(new BigDecimal("100"));
                        final BigDecimal shortageQuantity = shortageData.getShortageQuantity();
//                        final BigDecimal ddd = shortageQuantity.multiply(quota.divide(new BigDecimal("100")));
                        shortageData.setShortageQuantity(shortageQuantity);
                        shortageData.setRemark(itDatum.ZTEXT);
                        shortageData.setMainMaterialReply(itDatum.ZBZ2);
                        shortageData.setMainMaterialReplyDate(StringUtils.isNotEmpty(itDatum.EINDT)? DateUtils.formatYYYYMMDD(itDatum.EINDT):null);
                        shortageDataInsertLists.add(shortageData);
//                    }
                } else {
                    ShortageData shortageData = new ShortageData();
                    shortageDetailConvert.fillData(shortageData, shortageDetail);
                    shortageData.setId(null);
                    shortageData.setPlanId(planId);
                    shortageData.setType(ShortageDataType.MANUAL.getCode());
                    shortageData.setDetailId(id);
                    shortageData.setRemark(itDatum.ZTEXT);
                    shortageData.setMainMaterialReply(itDatum.ZBZ2);
                    shortageData.setMainMaterialReplyDate(StringUtils.isNotEmpty(itDatum.EINDT)? DateUtils.formatYYYYMMDD(itDatum.EINDT):null);
                    shortageDataInsertLists.add(shortageData);
                }
            }
            shortageDetailInsertLists.add(shortageDetail);
        }
        //查询数据库配置，是否启动以前的推送方法
        List<DictDTO> dictDTOS = dictClient.getDicByType("get_plan_data_method");
        String getPlanDateMethod = dictDTOS.get(0).getCode();
        if (StringUtils.isNotEmpty(getPlanDateMethod) && "Y".equals(getPlanDateMethod)) {
            System.out.println("启用即时推送即时存储欠料数据方法");
            if (CollUtil.isNotEmpty(shortageDataInsertLists)) {
                shortageDataService.saveBatch(shortageDataInsertLists, 300);
            }
            if (CollUtil.isNotEmpty(shortageDetailInsertLists)) {
                shortageDetailService.saveBatch(shortageDetailInsertLists, 300);
            }
            return ApiResult.builder().code(RestCode.SAP_SUCCESS.getCode()).build();
        }

        LocalTime nowTime = LocalTime.now();
        long secondsUntilMidnight = 86400 - nowTime.toSecondOfDay();
        Integer synTimes = 1;
        //全局控制，当次sap推过来的数据是否已经完成。 邓京术 2025-03-24
        stringRedisTemplate.opsForValue().set("dateNumber_syn", "N",secondsUntilMidnight, TimeUnit.SECONDS);
        if (CollUtil.isNotEmpty(shortageDataInsertLists)) {
            if (null != stringRedisTemplate.opsForValue().get("dateNumber")) {
                String dateNumberTemp = stringRedisTemplate.opsForValue().get("dateNumber");
                String[] dateNumberArr = dateNumberTemp.split("@@");
                //判断是否已经有同一批次的推送
                boolean flag = false;
                for (String str : dateNumberArr) {
                    //判断推送的批次是否一样
                    if (str.equals(dateNumber)) {
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    stringRedisTemplate.opsForValue().set("dateNumber", stringRedisTemplate.opsForValue().get("dateNumber") + "@@" + dateNumber, secondsUntilMidnight, TimeUnit.SECONDS);
                }
            } else {
                stringRedisTemplate.opsForValue().set("dateNumber", dateNumber, secondsUntilMidnight, TimeUnit.SECONDS);
            }

            if (null == stringRedisTemplate.opsForValue().get(dateNumber + "_times")) {
                stringRedisTemplate.opsForValue().set(dateNumber + "_times", String.valueOf(synTimes),secondsUntilMidnight, TimeUnit.SECONDS);
            } else {
                synTimes = Integer.parseInt(stringRedisTemplate.opsForValue().get(dateNumber + "_times")) + 1;
                stringRedisTemplate.opsForValue().set(dateNumber + "_times", String.valueOf(synTimes),secondsUntilMidnight, TimeUnit.SECONDS);
            }
            //判断数据是否推送完成
            if (null != plan.getSynStatus() && "接收完成".equals(plan.getSynStatus())) {
                stringRedisTemplate.opsForValue().set(dateNumber + "_max_times", String.valueOf(synTimes),secondsUntilMidnight, TimeUnit.SECONDS);
            }
            redisTemplate.opsForValue().set(dateNumber + "_shortageData_" + synTimes, com.alibaba.fastjson2.JSON.toJSONString(shortageDataInsertLists),secondsUntilMidnight, TimeUnit.SECONDS);
            stringRedisTemplate.opsForValue().set(dateNumber + "_syn_shortageData_" + synTimes, "N",secondsUntilMidnight, TimeUnit.SECONDS);
        }
        if (CollUtil.isNotEmpty(shortageDetailInsertLists)) {
            redisTemplate.opsForValue().set(dateNumber + "_shortageDetail_" + synTimes, com.alibaba.fastjson2.JSON.toJSONString(shortageDetailInsertLists),secondsUntilMidnight, TimeUnit.SECONDS);
            stringRedisTemplate.opsForValue().set(dateNumber + "_syn_shortageDetail_" + synTimes, "N",secondsUntilMidnight, TimeUnit.SECONDS);
        }
        stringRedisTemplate.opsForValue().set("dateNumber_syn", "Y",secondsUntilMidnight, TimeUnit.SECONDS);
        return ApiResult.builder().code(RestCode.SAP_SUCCESS.getCode()).build();
    }

    private void rebackShortAgeDataAndDetail(String dateNumber, ShortagePlan plan) {
        if (StringUtils.isNotEmpty(dateNumber)) {
            shortagePlanService.removeById(plan);
            shortageDataService.delShortAgeDataBySerialNumber(dateNumber);
            shortageDataService.delShortAgeDetailBySerialNumber(dateNumber);
            //同时清空redis缓存
            stringRedisTemplate.delete("dateNumber");
        }
    }
}