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.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.ErpProcessPageReqVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpProcessRespVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpProcessSaveReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpProcessDO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpProcessDetailDO;
import com.zt.plat.module.erp.dal.mysql.erp.ErpProcessMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

/**
 * ERP工艺路线 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class ErpProcessServiceImpl implements ErpProcessService {

    @Resource
    private ErpProcessMapper erpProcessMapper;

    @Resource
    private MyRedisConfig myRedisConfig;

    @Resource
    private ErpConfig erpConfig;

    @Resource
    private ErpProcessDetailServiceImpl processDetailService;


    @Override
    public ErpProcessRespVO createErpProcess(ErpProcessSaveReqVO createReqVO) {
        // 插入
        ErpProcessDO erpProcess = BeanUtils.toBean(createReqVO, ErpProcessDO.class);
        erpProcessMapper.insert(erpProcess);
        // 返回
        return BeanUtils.toBean(erpProcess, ErpProcessRespVO.class);
    }

    @Override
    public void updateErpProcess(ErpProcessSaveReqVO updateReqVO) {
        // 校验存在
        validateErpProcessExists(updateReqVO.getId());
        // 更新
        ErpProcessDO updateObj = BeanUtils.toBean(updateReqVO, ErpProcessDO.class);
        erpProcessMapper.updateById(updateObj);
    }

    @Override
    public void deleteErpProcess(Long id) {
        // 校验存在
        validateErpProcessExists(id);
        // 删除
        erpProcessMapper.deleteById(id);
    }

    @Override
    public void deleteErpProcessListByIds(List<Long> ids) {
        // 校验存在
        validateErpProcessExists(ids);
        // 删除
        erpProcessMapper.deleteByIds(ids);
    }

    private void validateErpProcessExists(List<Long> ids) {
        List<ErpProcessDO> list = erpProcessMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ERP_PROCESS_NOT_EXISTS);
        }
    }

    private void validateErpProcessExists(Long id) {
        if (erpProcessMapper.selectById(id) == null) {
            throw exception(ERP_PROCESS_NOT_EXISTS);
        }
    }

    @Override
    public ErpProcessDO getErpProcess(Long id) {
        return erpProcessMapper.selectById(id);
    }

    @Override
    public PageResult<ErpProcessDO> getErpProcessPage(ErpProcessPageReqVO pageReqVO) {
        return erpProcessMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional
    @XxlJob("getErpProcessTask")
    public void callErpRfcInterface() {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.工艺路线;
        String funcnr = funcnrEnum.getFuncnr();
        String key = "erpMap" + funcnr;
        if (myRedisConfig.getRedisCacheMap(key).isEmpty()) {
            initializeMap(key);
        }
        Map<String, Object> req = new HashMap<>();
        JSONArray dataArrayALL = new JSONArray();
        String factKey = "erpMap" + OftenEnum.FuncnrEnum.工厂信息.getFuncnr();
        Map<String, Long> redisCache = myRedisConfig.getRedisCacheMap(factKey);
        if (CollUtil.isEmpty(redisCache)) {
            throw exception(ERP_FACTORY_NOT_EXISTS);
        }
        // 1. 调用ERP接口获取数据
        for (String factoryNumber : redisCache.keySet()) {
            req.put("WERKS", factoryNumber);
            // 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_PROCESS_NOT_EXISTS);
        }

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

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

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

        List<ErpProcessDetailDO> erpProcessDetailDOList = new ArrayList<>();
        Map<String, Long> addnumbers = new HashMap<>();
        List<String> dataArrayNumbers = new ArrayList<>();

        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                ErpProcessDO DO = new ErpProcessDO();
                DO.setFactoryNumber(dataJson.getString("WERKS").trim());
                DO.setMaterialNumber(dataJson.getString("MATNR").trim());
                DO.setMaterialName(dataJson.getString("MAKTX").trim());
                DO.setBlineGroup(dataJson.getString("PLNAL").trim());
                Long groupCount = null;
                String plnnrStr = dataJson.getString("PLNNR");
                if (plnnrStr != null && !plnnrStr.trim().isEmpty()) {
                    try {
                        groupCount = Long.valueOf(plnnrStr.trim());
                    } catch (NumberFormatException e) {
                        log.error("转换PLNNR为Long类型失败: " + plnnrStr, e);
                    }
                }
                DO.setGroupCount(groupCount);
                DO.setBlineDescription(dataJson.getString("KTEXT").trim());
                DO.setUom(dataJson.getString("PLNME").trim());
                DO.setUseDescription(dataJson.getString("VERWE").trim());
                DO.setStatus(dataJson.getString("STATU").trim());
                String number = DO.getFactoryNumber() + "-" + DO.getMaterialNumber() + "-" + DO.getBlineGroup().trim()+"-" + DO.getGroupCount();
                dataArrayNumbers.add(number);
                if (numbers.get(number) != null) {
                    // 更新
                    DO.setId(numbers.get(number));
                    toUpdate.add(DO);
                } else {
                    // 新增
                    erpProcessMapper.insert(DO);
                    addnumbers.put(number, DO.getId());
                }

                JSONArray dataJsonItem = dataJson.getJSONArray("ITEM");
                if (dataJsonItem != null && !dataJsonItem.isEmpty()) {
                    for (int j = 0; j < dataJsonItem.size(); j++) {
                        JSONObject itemJson = dataJsonItem.getJSONObject(j);
                        ErpProcessDetailDO detailDO = new ErpProcessDetailDO();
                        detailDO.setProcessId(String.valueOf(DO.getId()));
                        String processingNumber = itemJson.getString("VORNR");
                        if (processingNumber != null) {
                            processingNumber = processingNumber.replaceFirst("^0+(?!$)", "");
                        }
                        detailDO.setProcessingNumber(processingNumber);
                        detailDO.setProcessingName(itemJson.getString("LTXA1"));
                        detailDO.setUom(itemJson.getString("MEINH"));
                        detailDO.setWorkCenterNumber(itemJson.getString("ARBPL"));
                        detailDO.setWorkCenterName(itemJson.getString("KTEXT1"));
                        erpProcessDetailDOList.add(detailDO);
                    }
                }
            }
        }

        // 识别需要删除的数据
        List<String> deleteNumbers = new ArrayList<>();
        for (String number : numbers.keySet()) {
            if (!dataArrayNumbers.contains(number)) {
                deleteNumbers.add(number);
            }
        }

        return new ProcessingResult(toUpdate, key, addnumbers, deleteNumbers, erpProcessDetailDOList);
    }

    /**
     * 批量保存数据
     */
    private void saveData(ProcessingResult result) {
        // 批量新增和更新
        if (!result.toUpdate.isEmpty()) {
            erpProcessMapper.updateBatch(result.toUpdate);
        }
        // 保存或更新BOM详情
        if (!result.erpProcessDetailDOList.isEmpty()) {
            processDetailService.saveOrUpdateErpProcessDetail(result.erpProcessDetailDOList);
        }

        // 更新Redis缓存
        if (!result.addnumbers.isEmpty()) {
            myRedisConfig.addRedisCacheMap(result.key, result.addnumbers);
        }

        if (!result.deleteNumbers.isEmpty()) {
            myRedisConfig.deleteRedisCacheMap(result.key, result.deleteNumbers);
        }
    }

    /**
     * 数据处理结果封装类
     */
    private static class ProcessingResult {
        private final List<ErpProcessDO> toUpdate;
        private final String key;
        private final Map<String, Long> addnumbers;
        private final List<String> deleteNumbers;
        private final List<ErpProcessDetailDO> erpProcessDetailDOList;

        public ProcessingResult(List<ErpProcessDO> toUpdate, String key, Map<String, Long> addnumbers,
                                List<String> deleteNumbers, List<ErpProcessDetailDO> erpProcessDetailDOList) {
            this.toUpdate = toUpdate;
            this.key = key;
            this.addnumbers = addnumbers;
            this.deleteNumbers = deleteNumbers;
            this.erpProcessDetailDOList = erpProcessDetailDOList;
        }
    }

    private void initializeMap(String key) {
        List<ErpProcessDO> bomList = erpProcessMapper.selectList(new LambdaQueryWrapperX<ErpProcessDO>());
        Map<String, Long> existingNumbers = new HashMap<>();
        for (ErpProcessDO bom : bomList) {
            String mapKey = bom.getFactoryNumber() + "-" + bom.getMaterialNumber() + "-" + bom.getBlineGroup()+"-" + bom.getGroupCount();
            existingNumbers.put(mapKey, bom.getId());
        }
        myRedisConfig.addRedisCacheMap(key, existingNumbers);
    }
}