package com.zt.plat.module.erp.service.erp;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpProductiveVersionPageReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpProductiveVersionDO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpPurchaseOrganizationDO;
import com.zt.plat.module.erp.utils.ErpConfig;
import com.zt.plat.module.erp.utils.MyRedisConfig;
import com.zt.plat.module.erp.enums.OftenEnum;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpProductiveOrderPageReqVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpProductiveOrderRespVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpProductiveOrderSaveReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpProductiveOrderDO;
import com.zt.plat.module.erp.dal.mysql.erp.ErpProductiveOrderMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.erp.enums.ErrorCodeConstants.*;
import static dm.jdbc.util.DriverUtil.log;

/**
 * ERP生产订单 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class ErpProductiveOrderServiceImpl implements ErpProductiveOrderService {

    @Resource
    private ErpProductiveOrderMapper erpProductiveOrderMapper;

    @Resource
    private ErpConfig erpConfig;
    @Resource
    private MyRedisConfig myRedisConfig;

    @Override
    public ErpProductiveOrderRespVO createErpProductiveOrder(ErpProductiveOrderSaveReqVO createReqVO) {
        // 插入
        ErpProductiveOrderDO erpProductiveOrder = BeanUtils.toBean(createReqVO, ErpProductiveOrderDO.class);
        erpProductiveOrderMapper.insert(erpProductiveOrder);
        // 返回
        return BeanUtils.toBean(erpProductiveOrder, ErpProductiveOrderRespVO.class);
    }

    @Override
    public void updateErpProductiveOrder(ErpProductiveOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateErpProductiveOrderExists(updateReqVO.getId());
        // 更新
        ErpProductiveOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductiveOrderDO.class);
        erpProductiveOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteErpProductiveOrder(Long id) {
        // 校验存在
        validateErpProductiveOrderExists(id);
        // 删除
        erpProductiveOrderMapper.deleteById(id);
    }

    @Override
    public void deleteErpProductiveOrderListByIds(List<Long> ids) {
        // 校验存在
        validateErpProductiveOrderExists(ids);
        // 删除
        erpProductiveOrderMapper.deleteByIds(ids);
    }

    private void validateErpProductiveOrderExists(List<Long> ids) {
        List<ErpProductiveOrderDO> list = erpProductiveOrderMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ERP_PRODUCTIVE_ORDER_NOT_EXISTS);
        }
    }

    private void validateErpProductiveOrderExists(Long id) {
        if (erpProductiveOrderMapper.selectById(id) == null) {
            throw exception(ERP_PRODUCTIVE_ORDER_NOT_EXISTS);
        }
    }

    @Override
    public ErpProductiveOrderDO getErpProductiveOrder(Long id) {
        return erpProductiveOrderMapper.selectById(id);
    }

//    @Override
//    public PageResult<ErpProductiveOrderDO> getErpProductiveOrderPage(ErpProductiveOrderPageReqVO pageReqVO) {
//        return erpProductiveOrderMapper.selectPage(pageReqVO);
//    }

    //    直接从erp查询生产订单
    @Override
    public PageResult<ErpProductiveOrderDO> getErpProductiveOrderPage(ErpProductiveOrderPageReqVO pageReqVO) {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.生产订单明细;
        String funcnr = funcnrEnum.getFuncnr();
        Map<String, Object> req = new HashMap<>();

        // 构建查询参数
        req.put("BUKRS", pageReqVO.getCompanyNumber());
        req.put("WERKS", pageReqVO.getFactoryNumber());

        // 处理日期参数
        if (pageReqVO.getStartDate() != null) {
            req.put("BEGDA", pageReqVO.getStartDate()[0].format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        }
        if (pageReqVO.getEndDate() != null) {
            req.put("ENDDA", pageReqVO.getEndDate()[0].format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        }

        // 调用ERP接口获取数据
        Map<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, req);
        JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
        if (dataArray == null || dataArray.isEmpty()) {
            // 返回空结果而不是抛出异常
            return new PageResult<>(new ArrayList<>(), 0L);
        }

        List<ErpProductiveOrderDO> list = new ArrayList<>();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                ErpProductiveOrderDO orderDO = new ErpProductiveOrderDO();

                // 基本信息
                orderDO.setCompanyNumber(dataJson.getString("BUKRS"));
                orderDO.setFactoryNumber(dataJson.getString("WERKS").trim());
                orderDO.setFactoryName(dataJson.getString("NAME1"));
                orderDO.setOrderNumber(dataJson.getString("AUFNR"));

                // 日期处理
                String plannedStartDate = dataJson.getString("GLTRP");
                String actualStartDate = dataJson.getString("GSTRP");

                if (plannedStartDate != null && !plannedStartDate.equals("0000-00-00")) {
                    try {
                        orderDO.setStartDate(LocalDateTime.parse(plannedStartDate));
                    } catch (Exception e) {
                        // 忽略日期解析错误
                    }
                }

                if (actualStartDate != null && !actualStartDate.equals("0000-00-00")) {
                    try {
                        orderDO.setEndDate(LocalDateTime.parse(actualStartDate));
                    } catch (Exception e) {
                        // 忽略日期解析错误
                    }
                }

                // 物料和工艺信息
                orderDO.setMainMaterialNumber(dataJson.getString("STLBEZ"));
                orderDO.setUnit(dataJson.getString("GMEIN"));
                orderDO.setMaterialDescription(dataJson.getString("MAKTX"));
                orderDO.setProcessingList(dataJson.getString("L_AFVC"));
                orderDO.setProcessingNumber(dataJson.getString("VORNR"));
                orderDO.setProcessingDescription(dataJson.getString("LTXA1"));
                orderDO.setObjectNumber(dataJson.getString("OBJID"));
                orderDO.setWorkCenterNumber(dataJson.getString("ARBPL"));
                orderDO.setWorkCenterDescription(dataJson.getString("KTEXT"));
                orderDO.setCostcenterNumber(dataJson.getString("KOSTL"));
                orderDO.setCostcenterName(dataJson.getString("TEXT_C"));

                list.add(orderDO);
            }
        }

        List<ErpProductiveOrderDO> listLast = list.stream()
                .filter(orderDO -> pageReqVO.getFactoryName() == null || pageReqVO.getFactoryName().equals(orderDO.getFactoryName()))
                .filter(orderDO -> pageReqVO.getOrderNumber() == null || pageReqVO.getOrderNumber().equals(orderDO.getOrderNumber()))
                .filter(orderDO -> pageReqVO.getMainMaterialNumber() == null || pageReqVO.getMainMaterialNumber().equals(orderDO.getMainMaterialNumber()))
                .filter(orderDO -> pageReqVO.getProcessingList() == null || pageReqVO.getProcessingList().equals(orderDO.getProcessingList()))
                .filter(orderDO -> pageReqVO.getProcessingNumber() == null || pageReqVO.getProcessingNumber().equals(orderDO.getProcessingNumber()))
                .filter(orderDO -> pageReqVO.getProcessingDescription() == null || pageReqVO.getProcessingDescription().equals(orderDO.getProcessingDescription()))
                .filter(orderDO -> pageReqVO.getObjectNumber() == null || pageReqVO.getObjectNumber().equals(orderDO.getObjectNumber()))
                .filter(orderDO -> pageReqVO.getWorkCenterNumber() == null || pageReqVO.getWorkCenterNumber().equals(orderDO.getWorkCenterNumber()))
                .filter(orderDO -> pageReqVO.getWorkCenterDescription() == null || pageReqVO.getWorkCenterDescription().equals(orderDO.getWorkCenterDescription()))
                .filter(orderDO -> pageReqVO.getCostcenterNumber() == null || pageReqVO.getCostcenterNumber().equals(orderDO.getCostcenterNumber()))
                .filter(orderDO -> pageReqVO.getCostcenterName() == null || pageReqVO.getCostcenterName().equals(orderDO.getCostcenterName()))
                .toList();

        // 返回分页结果
        return new PageResult<>(listLast, (long) listLast.size());
    }

    @Override
    @Transactional
//    @XxlJob("getErpProductiveOrderTask")
    public void callErpRfcInterface() {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.生产订单明细;
        String funcnr = funcnrEnum.getFuncnr();

        //防止缓存数据丢失
        String key = "erpMap" + funcnrEnum.getFuncnr();
        if (myRedisConfig.getRedisCacheMap(key).isEmpty()) {
            initializeMap(key);
        }
        Map<String, Object> req = new HashMap<>();
        List<Map<String, String>> datumListS = new ArrayList<>();
        Map<String, String> datumEntryS = new HashMap<>();
        // 构建datum参数数组
        datumEntryS.put("sign", "I");
        datumEntryS.put("option", "EQ");
        datumEntryS.put("low", LocalDate.now().toString());
        datumListS.add(datumEntryS);
        req.put("BEGDA", datumListS);
        List<Map<String, String>> datumListE = new ArrayList<>();
        Map<String, String> datumEntryE = new HashMap<>();
        // 构建datum参数数组
        datumEntryE.put("sign", "I");
        datumEntryE.put("option", "EQ");
        datumEntryE.put("low", LocalDate.now().toString());
        datumListE.add(datumEntryE);
        req.put("ENDDA", datumListE);
        JSONArray dataArrayALL = new JSONArray();
        List<String> redisCacheF = myRedisConfig.getRedisCache(OftenEnum.FuncnrEnum.工厂信息.getFuncnr());
        if (CollUtil.isEmpty(redisCacheF)) {
            throw exception(ERP_FACTORY_NOT_EXISTS);
        }
        List<String> redisCacheC = myRedisConfig.getRedisCache(OftenEnum.FuncnrEnum.公司代码.getFuncnr());
        if (CollUtil.isEmpty(redisCacheC)) {
            throw exception(ERP_FACTORY_NOT_EXISTS);
        }
        // 1. 调用ERP接口获取数据
        for (String numberC : redisCacheC) {
            for (String numberF : redisCacheF) {
                req.put("BUKRS", numberC);
                req.put("WERKS", numberF);
                // 1. 调用ERP接口获取数据
                Map<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, req);
                JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
                if (dataArray == null || dataArray.isEmpty()) {
                    continue;
                }
                dataArrayALL.addAll(dataArray);
            }
        }

        if (dataArrayALL.isEmpty()) {
            throw exception(ERP_PRODUCTIVE_ORDER_NOT_EXISTS);
        }

        // 2. 处理公司数据，区分新增和更新
        ProcessingResult result = processData(dataArrayALL, funcnrEnum);

        // 3. 批量保存数据
        saveData(result);
    }

    /**
     * 处理数据，区分新增和更新
     */
    private ProcessingResult processData(JSONArray dataArray, OftenEnum.FuncnrEnum funcnr) {
        String key = "erpMap" + funcnr.getFuncnr();
        Map<String, Long> numbers = myRedisConfig.getRedisCacheMap(key);
        List<ErpProductiveOrderDO> toUpdate = new ArrayList<>();
        List<ErpProductiveOrderDO> toInsert = new ArrayList<>();

        List<String> dataArrayNumbers = new ArrayList<>();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                String number = dataJson.getString("AUFNR").trim();
                ErpProductiveOrderDO DO = new ErpProductiveOrderDO();
                DO.setCompanyNumber(dataJson.getString("BUKRS").trim());
                DO.setFactoryNumber(dataJson.getString("WERKS").trim());
                DO.setFactoryName(dataJson.getString("NAME1").trim());
                DO.setOrderNumber(dataJson.getString("AUFNR").trim());
                if (!dataJson.getString("GLTRP").equals("0000-00-00")) {
                    DO.setStartDate(LocalDateTime.parse(dataJson.getString("GLTRP") + "T00:00:00"));
                }
                if (!dataJson.getString("GSTRP").equals("0000-00-00")) {
                    DO.setEndDate(LocalDateTime.parse(dataJson.getString("GSTRP") + "T00:00:00"));
                }
                DO.setMainMaterialNumber(dataJson.getString("STLBEZ").trim());
                DO.setUnit(dataJson.getString("GMEIN").trim());
                DO.setMaterialDescription(dataJson.getString("MAKTX").trim());
                DO.setProcessingList(dataJson.getString("L_AFVC").trim());
                DO.setProcessingNumber(dataJson.getString("VORNR").trim());
                DO.setProcessingDescription(dataJson.getString("LTXA1").trim());
                DO.setObjectNumber(dataJson.getString("OBJID").trim());
                DO.setWorkCenterNumber(dataJson.getString("ARBPL").trim());
                DO.setWorkCenterDescription(dataJson.getString("KTEXT").trim());
                DO.setCostcenterNumber(dataJson.getString("KOSTL").trim());
                DO.setCostcenterName(dataJson.getString("TEXT_C").trim());
                if (numbers.get(number) != null) {
                    // 更新
                    DO.setId(numbers.get(number));
                    toUpdate.add(DO);
                } else {
                    // 新增
                    toInsert.add(DO);
                }
                dataArrayNumbers.add(number);
            }
        }
        // 过滤出numbers中有，但dataArray中KOSTL没有的记录，即为需要删除的数据
        List<String> deleteNumbers = new ArrayList<>();
        for (String number : numbers.keySet()) {
            if (!dataArrayNumbers.contains(number)) {
                deleteNumbers.add(number);
            }
        }

        return new ProcessingResult(toUpdate, toInsert, key, deleteNumbers);
    }

    /**
     * 批量保存数据
     */
    private void saveData(ProcessingResult result) {
        // 批量新增和更新
        if (!result.toInsert.isEmpty()) {
            erpProductiveOrderMapper.insertBatch(result.toInsert);
            // 批量查询刚插入数据的id，提升效率
            List<String> insertedNumbers = result.toInsert.stream()
                    .map(ErpProductiveOrderDO::getOrderNumber)
                    .collect(Collectors.toList());
            List<ErpProductiveOrderDO> insertedRecords = erpProductiveOrderMapper.selectList(
                    new LambdaQueryWrapperX<ErpProductiveOrderDO>()
                            .in(ErpProductiveOrderDO::getOrderNumber, insertedNumbers)
            );
            Map<String, Long> numberIdMap = insertedRecords.stream()
                    .collect(Collectors.toMap(ErpProductiveOrderDO::getOrderNumber, ErpProductiveOrderDO::getId));
            myRedisConfig.addRedisCacheMap(result.key, numberIdMap);
        }
        if (!result.toUpdate.isEmpty()) {
            erpProductiveOrderMapper.updateBatch(result.toUpdate);
        }
        if (!result.deleteNumbers.isEmpty()) {
            // 使用 in 条件批量删除，提高删除效率
            erpProductiveOrderMapper.delete(new LambdaQueryWrapperX<ErpProductiveOrderDO>().in(ErpProductiveOrderDO::getOrderNumber, result.deleteNumbers));
            myRedisConfig.deleteRedisCacheMap(result.key, result.deleteNumbers);
        }
    }

    /**
     * 数据处理结果封装类
     */
    private static class ProcessingResult {
        private final List<ErpProductiveOrderDO> toUpdate;
        private final List<ErpProductiveOrderDO> toInsert;
        private final String key;
        private final List<String> deleteNumbers;

        public ProcessingResult(List<ErpProductiveOrderDO> toUpdate, List<ErpProductiveOrderDO> toInsert, String key, List<String> deleteNumbers) {
            this.toUpdate = toUpdate;
            this.toInsert = toInsert;
            this.key = key;
            this.deleteNumbers = deleteNumbers;
        }
    }


    private void initializeMap(String key) {
        List<ErpProductiveOrderDO> assets = erpProductiveOrderMapper.selectList(new LambdaQueryWrapperX<ErpProductiveOrderDO>());
        Map<String, Long> existingNumbers = new HashMap<>();
        for (ErpProductiveOrderDO asset : assets) {
            String mapKey = asset.getOrderNumber();
            existingNumbers.put(mapKey, asset.getId());
        }
        myRedisConfig.addRedisCacheMap(key, existingNumbers);
    }
}