package com.emergency.avenue.storage.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.emergency.avenue.storage.api.entity.DockErrorLogDO;
import com.emergency.avenue.storage.api.entity.DockOrganizationDO;
import com.emergency.avenue.storage.api.entity.DockStockInfoDO;
import com.emergency.avenue.storage.job.HmacUtil;
import com.emergency.avenue.storage.mapper.StockDataDockingMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.Response;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: report-java
 * @author: duhuajie
 * @create: 2024-07-26
 * @description: 库存对接 service
 */

@Service
public class StockDataDockingService {

    @Resource
    private StockDataDockingMapper stockDataDockingMapper;

    /**
     * 对接机构信息
     */
    public void dockingOrganization() {
        // 查询（所有）机构信息
        List<DockOrganizationDO> organizationList =  stockDataDockingMapper.selectOrganization();

        // 查询（所有）对接机构信息
        List<DockOrganizationDO> dockingOrganizationList =  stockDataDockingMapper.selectOrganizationAll();
        // 处理数据
        // 保存到对接表
        // 调用接口对接
        // 获取返回值，修改对接状态
    }

    /**
     * 对接仓库信息
     */
    public void dockingWarehouse() {
        // 查询
        // 处理数据
        // 调用接口对接
        // 获取返回值，修改对接状态
    }

    /**
     * 对接库存信息
     */
    public void dockingStock() {
        // 查询
        List<DockStockInfoDO> organizationList =  stockDataDockingMapper.selectStockInfoList();

        if(organizationList.isEmpty()){
            return;
        }

        List<DockErrorLogDO> errorLogs = new ArrayList<>();

        //处理数据
        List<DockStockInfoDO> dockStockInfoDOS = processStockInfoList(organizationList, errorLogs);

        // 对比数据，分出需要新增和变更的数据 变更要把upload 改成 0
        processNewAndOldData(dockStockInfoDOS);


        // 存入错误日志
        for (DockErrorLogDO errorLogDO : errorLogs) {
            stockDataDockingMapper.insertErrorLog(errorLogDO);
        }

    }

    private void processNewAndOldData(List<DockStockInfoDO> organizationList) {
        List<DockStockInfoDO> oldData = stockDataDockingMapper.selectList(Wrappers.emptyWrapper());
        if(oldData.isEmpty()){
            //存入数据库
            for (DockStockInfoDO dockStockInfoDO : organizationList) {
                stockDataDockingMapper.insert(dockStockInfoDO);
            }
            return;
        }
        List<DockStockInfoDO> updateData = new ArrayList<>();
        List<DockStockInfoDO> newDataList = new ArrayList<>();

        for (DockStockInfoDO newData : organizationList) {
            boolean flag = false;
            for (DockStockInfoDO old : oldData) {
                if(old.getUniqueIdentification().equals(newData.getUniqueIdentification())){
                    // 数据有变化，修改upload为0，重新对接
                    if(newData.getRealNum().compareTo(old.getRealNum()) != 0 || newData.getUsableNum().compareTo(old.getUsableNum()) != 0){
                        updateData.add(newData);
                        newData.setId(old.getId());
                        newData.setUpload(0);
                    }
                    // 数据无变化，不做处理
                    flag = true;
                }
            }
            // 新数据，新增到对接表
            if(!flag){
                newDataList.add(newData);
            }
        }

        //存入数据库
        for (DockStockInfoDO dockStockInfoDO : newDataList) {
            stockDataDockingMapper.insert(dockStockInfoDO);
        }
        //变更数据
        for (DockStockInfoDO dockStockInfoDO : updateData) {
            stockDataDockingMapper.updateById(dockStockInfoDO);
        }

    }

    public void dockingStock2() {
        LambdaQueryWrapper<DockStockInfoDO> eq = Wrappers.<DockStockInfoDO>query().lambda().eq(DockStockInfoDO::getUpload, 0);
        List<DockStockInfoDO> dockStockInfoDOS = stockDataDockingMapper.selectList(eq);
        List<DockErrorLogDO> errorLogs = new ArrayList<>();
        if (!dockStockInfoDOS.isEmpty()) {
            if (dockStockInfoDOS.size() <= 20) {
                dockingData(dockStockInfoDOS, errorLogs);
            } else {
                // 拆分列表并调用对接方法
                int size = dockStockInfoDOS.size();
                for (int i = 0; i < size; i += 20) {
                    int end = Math.min(size, i + 20);
                    List<DockStockInfoDO> subList = dockStockInfoDOS.subList(i, end);
                    dockingData(subList, errorLogs);
                }
            }
            // 变更 upload
            for (DockStockInfoDO dockStockInfoDO : dockStockInfoDOS) {
                if(dockStockInfoDO.getUpload() != 0){
                    DockStockInfoDO dockStockInfo = new DockStockInfoDO();
                    dockStockInfo.setId(dockStockInfoDO.getId());
                    dockStockInfo.setUpload(dockStockInfoDO.getUpload());
                    stockDataDockingMapper.updateById(dockStockInfo);
                }
            }
            // 存入错误日志
            for (DockErrorLogDO errorLogDO : errorLogs) {
                if(errorLogDO.getErrorReason().length()> 2048){
                    errorLogDO.setErrorReason(errorLogDO.getErrorReason().substring(0,2048));
                }
                if(errorLogDO.getErrorData().length()> 2048){
                    errorLogDO.setErrorData(errorLogDO.getErrorData().substring(0,2048));
                }
                stockDataDockingMapper.insertErrorLog(errorLogDO);
            }
        }
    }

    private void dockingData(List<DockStockInfoDO> organizationList, List<DockErrorLogDO> errorLogs) {
        DockErrorLogDO dockErrorLogDO = new DockErrorLogDO();
        dockErrorLogDO.setProjectName("库存对接");
        try {
            long l = System.currentTimeMillis();
            Map<String, Object> map = new HashMap<>();
            map.put("syncUniqueNo", l);
            map.put("stockList", organizationList);
            String anString = "";
            Response response = HmacUtil.dockingData(map);
            if (response.isSuccessful()) {
                if (response.body() != null) {
                    anString += response.body().string();
                } else {
                    dockErrorLogDO.setErrorReason("返回值空");
                    dockErrorLogDO.setErrorData(JSON.toJSONString(map));
                    errorLogs.add(dockErrorLogDO);
                    return;
                }
            } else {
                dockErrorLogDO.setErrorReason("接口访问异常");
                dockErrorLogDO.setErrorData(JSON.toJSONString(map));
                errorLogs.add(dockErrorLogDO);
                return;
            }
            ObjectMapper objectMapper = new ObjectMapper();
            if (anString.contains("error_response")) {
                dockErrorLogDO.setErrorReason("接口访问异常");
                dockErrorLogDO.setErrorData(anString);
                errorLogs.add(dockErrorLogDO);
                return;
            }
            JsonNode responseJson = objectMapper.readTree(anString);
            int code = responseJson.get("code").asInt();
            if (code == 200) {
                organizationList.forEach(item -> item.setUpload(1));
                dockErrorLogDO.setErrorReason("对接成功:"+anString);
                dockErrorLogDO.setErrorData(JSON.toJSONString(map));
                errorLogs.add(dockErrorLogDO);
            } else if (code == 206) {
                JsonNode dataNode = responseJson.get("data");
                if (dataNode != null && dataNode.isArray()) {
                    organizationList.forEach(item -> {
                        dataNode.forEach(data -> {
                            if (item.getOutWarehouseNo().equals(data.get("outWarehouseNo").asText())
                                    && item.getGoodsNo().equals(data.get("goodsNo").asText())
                                    && item.getUsableNum().toString().equals(data.get("usableNum").asText())) {
                                DockErrorLogDO dockErrorLog = new DockErrorLogDO();
                                dockErrorLog.setProjectName("库存对接");
                                dockErrorLog.setErrorReason("数据异常(单条）");
                                dockErrorLog.setErrorData(JSON.toJSONString(item));
                                errorLogs.add(dockErrorLog);
                                item.setUpload(2);
                            } else {
                                item.setUpload(1);
                            }
                        });
                    });
                }
            } else {
                dockErrorLogDO.setErrorReason("数据异常:"+anString);
                dockErrorLogDO.setErrorData(JSON.toJSONString(map));
                errorLogs.add(dockErrorLogDO);
                organizationList.forEach(item -> {
                    item.setUpload(2);
                });
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 处理入库数据-价值表-：如果有两条唯一标识相同的(物资名称、入库时间、单价、是否可用、部门)入库数据，
     * 防止多词扣减出库
     * 处理逻辑：
     * 	1. 按数量从小到大扣减，依次扣减，如果不够最后的一条为负数
     * @param inboundList 入库信息列表
     */
    public static  List<DockStockInfoDO> processStockInfoList(List<DockStockInfoDO> inboundList,List<DockErrorLogDO> errorLogs) {
        Set<String> errorStr = new HashSet<>();

        // 处理国标缺失数据
        for (int i = 0; i < inboundList.size(); i++) {
            DockStockInfoDO dockStockInfoDO = inboundList.get(i);
            boolean b = false;
            if(dockStockInfoDO.getWarehouseNo() == null ){
                errorStr.add("仓库编号,没有国标,"+ dockStockInfoDO.getOutWarehouseNo());
                b = true;
            }

            if(dockStockInfoDO.getGoodsNo() == null ){
                errorStr.add("物资编码,没有国标," + dockStockInfoDO.getOutGoodsNo());
                b = true;
            }

            if(dockStockInfoDO.getOwnerNo() == null ){
                errorStr.add("机构编码,没有国标," + dockStockInfoDO.getOutOwnerNo());
                b = true;
            }
            if(b){
                inboundList.remove(i);
                i--;
            }
        }

        for (String s : errorStr){
            DockErrorLogDO dockErrorLogDO = new DockErrorLogDO();
            dockErrorLogDO.setProjectName("库存对接");
            dockErrorLogDO.setErrorField(s.split(",")[0]);
            dockErrorLogDO.setErrorReason(s.split(",")[1]);
            dockErrorLogDO.setErrorData(s.split(",")[2]);
            dockErrorLogDO.setCreateTime(LocalDateTime.now());

            errorLogs.add(dockErrorLogDO);
        }
        //处理数量
        List<DockStockInfoDO> dockStockInfoDOS = processNum(inboundList);
        //处理批次属性串
        processBatchAttr(dockStockInfoDOS);
        return dockStockInfoDOS;
    }

    private static void processBatchAttr(List<DockStockInfoDO> inboundList) {
        for (DockStockInfoDO dockStockInfoDO : inboundList) {

            String unitPrice = dockStockInfoDO.getUnitPrice();
            String inboundTime = dockStockInfoDO.getInboundTime();
            String batchAttr = "单价:"+unitPrice;
            if(inboundTime != null && !inboundTime.isEmpty()){
                batchAttr = batchAttr + ",入库年月:"+inboundTime.substring(0,7);
            }
            dockStockInfoDO.setIsvLotattrs(batchAttr);
            dockStockInfoDO.setBatchCode("0");
        }
    }

    /**
     *  处理数量
     * @param inboundList 数据列表
     */
    private static  List<DockStockInfoDO> processNum(List<DockStockInfoDO> inboundList) {
        // 第一步：按唯一标识符分组
        Map<String, List<DockStockInfoDO>> groupedByUniqueId = inboundList.stream()
                .collect(Collectors.groupingBy(DockStockInfoDO::getUniqueIdentification));

        List<DockStockInfoDO> inboundList2 = new ArrayList<>();
        // 第二步：处理每个组
        for (Map.Entry<String, List<DockStockInfoDO>> entry : groupedByUniqueId.entrySet()) {
            List<DockStockInfoDO> sameUniqueIdList = entry.getValue();
            if (sameUniqueIdList.size()==1){
                inboundList2.add(sameUniqueIdList.get(0));
                continue;
            }
            DockStockInfoDO dockStockInfoDO = sameUniqueIdList.get(0);
            // 计算总出库数量和总价
            BigDecimal remainingQuantityOut = new BigDecimal(dockStockInfoDO.getQuantityOut());
            // 计算入库数量
            BigDecimal totalQuantityIn = sameUniqueIdList.stream().map(DockStockInfoDO::getQuantityIn).map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);

            totalQuantityIn = totalQuantityIn.subtract(remainingQuantityOut);
            dockStockInfoDO.setQuantity(totalQuantityIn.toString());
            inboundList2.add(dockStockInfoDO);
        }

        // 处理可用数量
        for (DockStockInfoDO item : inboundList2) {
            if("0".equals(item.getIsAvailable())) {
                // 可用
                item.setRealNum( new BigDecimal(item.getQuantity()).multiply(item.getUnitCoefficient()));
                item.setUsableNum( new BigDecimal(item.getQuantity()).multiply(item.getUnitCoefficient()));
            } else{
                item.setRealNum(new BigDecimal(item.getQuantity()).multiply(item.getUnitCoefficient()));
                item.setUsableNum(BigDecimal.ZERO);
            }
            item.setOccupyNum(BigDecimal.ZERO);
        }
        return inboundList2;
    }

    public static void main(String[] args) {
        DockOrganizationDO aa = new DockOrganizationDO();
        DockOrganizationDO bb = new DockOrganizationDO();
        System.out.println(aa.equals(bb));
    }
}
