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.api.BaseApi;
import com.zt.plat.module.api.dto.MaterialOtherDTO;
import com.zt.plat.module.erp.api.dto.ErpMaterialDTO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpWarehouseDO;
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.ErpMaterialPageReqVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpMaterialRespVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpMaterialSaveReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpMaterialDO;
import com.zt.plat.module.erp.dal.mysql.erp.ErpMaterialMapper;
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.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 ErpMaterialServiceImpl implements ErpMaterialService {

    @Resource
    private ErpMaterialMapper erpMaterialMapper;
    @Resource
    private BaseApi baseApi;
    @Resource
    private MyRedisConfig myRedisConfig;
    @Resource
    private ErpConfig erpConfig;

    @Override
    public ErpMaterialRespVO createErpMaterial(ErpMaterialSaveReqVO createReqVO) {
        // 校验存在
        validateErpFactoryExistsNumber(createReqVO.getDownCenterNumber());
        // 插入
        ErpMaterialDO erpMaterial = BeanUtils.toBean(createReqVO, ErpMaterialDO.class);
        // 工厂编码自动生成，格式 GC-0001,依次新增
        if (erpMaterial.getDownCenterNumber() == null) {
            String maxCode = erpMaterialMapper.selectMaxCode();
            if (maxCode == null) {
                erpMaterial.setDownCenterNumber("WL-0001");
            } else {
                String prefix = "WL-";
                String numberPart = maxCode.substring(prefix.length());
                int nextNumber = Integer.parseInt(numberPart) + 1;
                String nextCode = prefix + String.format("%04d", nextNumber);
                erpMaterial.setDownCenterNumber(nextCode);
            }
        }
        erpMaterial.setType("SPLY");
        erpMaterialMapper.insert(erpMaterial);
        // 返回
        return BeanUtils.toBean(erpMaterial, ErpMaterialRespVO.class);
    }

    @Override
    public void updateErpMaterial(ErpMaterialSaveReqVO updateReqVO) {
        // 校验存在
        validateErpMaterialExists(updateReqVO.getId());
        // 更新
        ErpMaterialDO updateObj = BeanUtils.toBean(updateReqVO, ErpMaterialDO.class);
        if (updateObj.getType().equals("SPLY")) {
            erpMaterialMapper.updateById(updateObj);
        } else {
            throw exception(ERP_MATERIAL_NOT_ALLOW_UPDATE);
        }
    }

    @Override
    public void deleteErpMaterial(Long id) {
        // 校验存在
        validateErpMaterialExists(id);
        // 删除
        erpMaterialMapper.deleteById(id);
    }

    @Override
    public void deleteErpMaterialListByIds(List<Long> ids) {
        // 校验存在
        validateErpMaterialExists(ids);
        // 删除
        erpMaterialMapper.deleteByIds(ids);
    }

    private void validateErpMaterialExists(List<Long> ids) {
        List<ErpMaterialDO> list = erpMaterialMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ERP_MATERIAL_NOT_EXISTS);
        }
        List<ErpMaterialDO> erpMaterialDOList = list.stream()
                .filter(erpMaterialDO -> erpMaterialDO.getType().equals("ERP"))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(erpMaterialDOList)) {
            throw exception(ERP_MATERIAL_NOT_ALLOW_DELETE);
        }
        // 优化成批量查询，使用IN语句
        List<String> downCenterNumbers = list.stream()
                .map(ErpMaterialDO::getDownCenterNumber)
                .collect(Collectors.toList());

        // 使用IN语句批量查询所有物料编码的数量
        Integer countMap = erpMaterialMapper.countByErpMNumbers(downCenterNumbers);
        if (countMap > 1) {
            throw exception(ERP_MATERIAL_OTHER_NOT_ALLOW_DELETE);
        }
    }

    private void validateErpMaterialExists(Long id) {
        if (erpMaterialMapper.selectById(id) == null) {
            throw exception(ERP_MATERIAL_NOT_EXISTS);
        }
    }

    private void validateErpFactoryExistsNumber(String number) {
        List<ErpMaterialDO> list = erpMaterialMapper.selectList(new LambdaQueryWrapperX<ErpMaterialDO>()).stream()
                .filter(erpWarehouseDO -> erpWarehouseDO.getDownCenterNumber().equals(number))
                .toList();
        if (!list.isEmpty()) {
            throw exception(ERP_MATERIAL_EXISTS);
        }
    }

    @Override
    public ErpMaterialDO getErpMaterial(Long id) {
        return erpMaterialMapper.selectById(id);
    }

    @Override
    public PageResult<ErpMaterialDO> getErpMaterialPage(ErpMaterialPageReqVO pageReqVO) {
        return erpMaterialMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<ErpMaterialRespVO> getErpMaterialPageAndOther(ErpMaterialPageReqVO pageReqVO) {
        try {
            PageResult<ErpMaterialDO> pageResult = erpMaterialMapper.selectPage(pageReqVO);
            PageResult<ErpMaterialRespVO> pageResultRespVo = BeanUtils.toBean(pageResult, ErpMaterialRespVO.class);
            for (ErpMaterialRespVO respVO : pageResultRespVo.getList()) {
                respVO.setMaterialNumber(respVO.getDownCenterNumber());
                MaterialOtherDTO dto = new MaterialOtherDTO();
                dto.setMaterialNumber(respVO.getDownCenterNumber());
                List<MaterialOtherDTO> dtos = baseApi.getMaterialOtherNoPage(dto);
                if (dtos != null) {
                    respVO.setMaterialOtherDTOS(dtos);
                }
            }
            return pageResultRespVo;
        } catch (Exception e) {
            throw exception(ERP_MATERIAL_NOT_EXISTS);
        }
    }

    @Override
    public String getMaterialUnit(String materialNumber) {
        return erpMaterialMapper.getMaterialUnit(materialNumber);
    }

    @Override
    @Transactional
    @XxlJob("getErpMaterialTask")
    public void callErpRfcInterface() {
        OftenEnum.FuncnrEnum funcnrEnum = OftenEnum.FuncnrEnum.物料数据;
        String funcnr = funcnrEnum.getFuncnr();
        //防止缓存数据丢失
        String key = "erp" + funcnrEnum.getFuncnr();
        if (myRedisConfig.getRedisCache(key) == null) {
            initialize(key);
        }

        // 构建req参数
        Map<String, Object> req = new HashMap<>();
        List<Map<String, String>> datumList = new ArrayList<>();
        Map<String, String> datumEntry = new HashMap<>();
        datumEntry.put("sign", "I");
        datumEntry.put("option", "EQ");
//            datumEntry.put("low", "2021-05-20");
        datumEntry.put("low", LocalDate.now().toString());
        datumList.add(datumEntry);
        req.put(funcnrEnum.getDatekey(), datumList);

        // 1. 调用ERP接口获取数据
        HashMap<String, Object> dataFromERP = erpConfig.fetchDataFromERP(funcnr, req);
        JSONArray dataArray = (JSONArray) dataFromERP.get("E_RESP");
        if (dataArray == null || dataArray.isEmpty()) {
            return;
        }

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

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

    /**
     * 处理数据，区分新增和更新
     */
    private ProcessingResult processData(JSONArray dataArray, OftenEnum.FuncnrEnum funcnr) {
        String key = "erp" + funcnr.getFuncnr();
        Map<String, List<String>> numbers = myRedisConfig.numbers(dataArray, key, funcnr.getDatakey());
        List<String> allnumbers = numbers.get("all");
        List<String> comnumbers = numbers.get("com");
        List<ErpMaterialDO> toUpdate = new ArrayList<>();
        List<ErpMaterialDO> toInsert = new ArrayList<>();

        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataJson = dataArray.getJSONObject(i);
            if (dataJson != null) {
                String number = dataJson.getString("MATNR").trim();
                ErpMaterialDO DO = new ErpMaterialDO();
                DO.setDownCenterNumber(number);
                DO.setCenterNumber(dataJson.getString("BISMT"));
                if (!dataJson.getString("ERSDA").equals("0000-00-00")) {
                    DO.setCreateDate(LocalDateTime.parse(dataJson.getString("ERSDA") + "T00:00:00"));
                }
                DO.setMaterialType(dataJson.getString("MTART"));
                DO.setMaterialGroupDate(dataJson.getString("MATKL"));
                DO.setExternalMaterialGroupDate(dataJson.getString("EXTWG"));
                DO.setUnit(dataJson.getString("MEINS"));
                DO.setUnitDescription(dataJson.getString("MSEHT"));
                DO.setMaterialTypeDescription(dataJson.getString("MTBEZ"));
                DO.setMaterialGroupDescription(dataJson.getString("WGBEZ"));
                DO.setExternalMaterialGroupDescription(dataJson.getString("EWBEZ"));
                DO.setMaterialName(dataJson.getString("MAKTX"));
                DO.setMaterialLengthDescription(dataJson.getString("LDESC"));
                DO.setType("ERP");

                if (comnumbers.contains(number)) {
                    // 更新
                    toUpdate.add(DO);
                } else {
                    // 新增
                    toInsert.add(DO);
                }
            }
        }

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

    /**
     * 批量保存数据
     */
    private void saveData(ProcessingResult result) {
        // 批量新增和更新
        if (!result.toInsert.isEmpty()) {
            erpMaterialMapper.insertBatch(result.toInsert);
        }
        if (!result.toUpdate.isEmpty()) {
            erpMaterialMapper.updateBatchByNumber(result.toUpdate);
        }
        myRedisConfig.updateRedisCache(result.key, result.allnumbers);
    }

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

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

    private void initialize(String key) {
        List<String> existingNumbers = erpMaterialMapper.selectList(new LambdaQueryWrapperX<ErpMaterialDO>())
                .stream()
                .filter(ErpMaterialDO -> ErpMaterialDO.getType().equals("ERP"))
                .map(ErpMaterialDO::getDownCenterNumber)
                .collect(Collectors.toList());
        myRedisConfig.updateRedisCache(key, existingNumbers);
    }
}