package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.base;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesPojoVersionService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.MesConfigService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.JsonUtilTool;
import cn.estsh.i3plus.platform.common.util.CommonConstWords;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.codemaker.SnowflakeIdMaker;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesPojoVersion;
import cn.estsh.i3plus.pojo.mes.bean.MesPojoVersionDetail;
import cn.estsh.i3plus.pojo.mes.repository.MesPojoVersionDetailRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesPojoVersionRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class MesPojoVersionServiceImpl implements IMesPojoVersionService {

    private static final Logger LOGGER = LoggerFactory.getLogger(MesPojoVersionServiceImpl.class);


    @Autowired
    private MesPojoVersionRepository mesPojoVersionRepository;


    @Autowired
    private MesPojoVersionDetailRepository mesPojoVersionDetailRepository;
    @Resource
    private SnowflakeIdMaker snowflakeIdMaker;

    @Autowired
    private MesConfigService mesConfigService;

    @Override
    public MesPojoVersion getPojoVersion(MesPojoVersion bean) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(bean);
        return mesPojoVersionRepository.getByProperty(DdlPackBean.getDdlPackBean(bean));
    }

    @Override
    public void insertPojoVersion(Object obj, Class cls) {
            try {
                MesPojoVersion version = getMesPojoVersion(obj, cls, "insert");
                recordPojoVersion(version);
            } catch (Exception e) {
                e.printStackTrace();
            }
    }

    @Override
    public void savePojoVersion(Object obj, Class cls) {
            try {
                MesPojoVersion version = getMesPojoVersion(obj, cls, "update");
                recordPojoVersion(version);
            } catch (Exception e) {
                e.printStackTrace();
            }

    }

    @Override
    public void insertPojoVersionList(List<Object> list, Class cls) {
        list.forEach(obj -> {
            try {
                MesPojoVersion version = getMesPojoVersion(obj, cls, "insert");
                recordPojoVersion(version);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
    @Override
    public void savePojoVersionList(List<Object> list, Class cls) {
        list.forEach(obj -> {
            try {
                MesPojoVersion version = getMesPojoVersion(obj, cls, "update");
                recordPojoVersion(version);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private MesPojoVersion getMesPojoVersion(Object obj, Class cls, String insert) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Method getIdmethod = cls.getMethod("getId");
        Method getCodemethod = cls.getMethod("getOrganizeCode");
        Long id = Long.valueOf(getIdmethod.invoke(obj).toString());
        String organizeCode = getCodemethod.invoke(obj).toString();
        MesPojoVersion version = new MesPojoVersion();
        version.setRefId(id);
        version.setRefClass(cls.getName());
        version.setBean(JsonUtilTool.encode(obj));
        version.setCreateUser(version.getCreateUser());
        version.setModifyUser(version.getModifyUser());
        version.setVersionMethodName(insert);
        version.setBusiData(getBusiData(cls, version.getRefClass(),obj));
        version.setOrganizeCode(organizeCode);
        return version;
    }

    public String getBusiData(Class cls, String refClass, Object obj){
        String busiData = "";
        try {
            MesExtEnumUtil.BUSI_REFERANCE busiReferance = MesExtEnumUtil.BUSI_REFERANCE.valueOfEnum(refClass);
            Method method = null;
            switch (busiReferance) {
                case MES_PRODUCE_SN:
                    method = cls.getMethod("getProductSn");
                    busiData = method.invoke(obj).toString();
                    break;
                case MES_WORK_ORDER:
                    method = cls.getMethod("getWorkOrderNo");
                    busiData = method.invoke(obj).toString();
                    break;
                case MES_SHIPPING_ORDER:
                    method = cls.getMethod("getShippingCode");
                    busiData = method.invoke(obj).toString();
                    break;
                default:
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return busiData;
    }

    @Override
    public void recordPojoVersion(MesPojoVersion afterMesPojoVersion) {

        MesPojoVersion beforePojoVersion = new MesPojoVersion();
        MesPojoVersionDetail beforePojoVersionDetail = new MesPojoVersionDetail();
        Map<String, Object> beforeMap = new HashMap<>();
        Map<String, Object> afterMap = JsonUtilTool.decode(afterMesPojoVersion.getBean(), Map.class);
        MesPojoVersionDetail afterPojoVersionDetail = null;

        String config = mesConfigService.getCfgValue(afterMesPojoVersion.getOrganizeCode(), "MARK_FILED");
        JSONObject reqJson = new JSONObject();
        if (!StringUtils.isEmpty(config)) {
            reqJson = JSONObject.parseObject(config);
        }

        Integer versionNo;                                                                      // 对象版本
        CommonEnumUtil.DAO_OPERATE_TYPE operateType = CommonEnumUtil.DAO_OPERATE_TYPE.INSERT;   // 操作类型
        Map<String, MapDifference.ValueDifference<Object>> mapDiff;                           // 版本对比
        String userName = StringUtils.isNotBlank(afterMesPojoVersion.getModifyUser()) ? afterMesPojoVersion.getModifyUser() : afterMesPojoVersion.getCreateUser();
        Map<String, String> mapPropDesc = afterMesPojoVersion.getPojoPropDesc();

        boolean isInsert = true;
        if (!"insert".equals(afterMesPojoVersion.getVersionMethodName())) {  // 不是新增数据的时候则需要查询历史记录
            // 已存在数据封装
            afterMesPojoVersion.setOrderByParam("createDatetime");
            afterMesPojoVersion.setAscOrDesc(CommonEnumUtil.ASC_OR_DESC.DESC.getValue());

            beforePojoVersion = this.getPojoVersion(afterMesPojoVersion);
            if (Objects.nonNull(beforePojoVersion)) {
                beforePojoVersionDetail = mesPojoVersionDetailRepository.getById(beforePojoVersion.getPojoDetailId());
                if (Objects.nonNull(beforePojoVersionDetail)) {
                    beforeMap.putAll(JsonUtilTool.decode(beforePojoVersionDetail.getPojoAfter(), Map.class));
                }
            }
            operateType = CommonEnumUtil.DAO_OPERATE_TYPE.UPDATE;
            isInsert = false;
        }
        // 不保存字段 数据剔除
        for (String key : CommonConstWords.POJO_VERSION_SAVE_ATTR_REMOVE) {
            afterMap.remove(key);
        }

        mapDiff = Maps.difference(beforeMap, afterMap).entriesDiffering();


        MesExtEnumUtil.BUSI_REFERANCE busiReferance = MesExtEnumUtil.BUSI_REFERANCE.valueOfEnum(afterMesPojoVersion.getRefClass());
        Method method = null;
        String statusKey = "";
        boolean isSave = false;
        List<String> statusList = new ArrayList<>();
        switch (busiReferance) {
            case MES_PRODUCE_SN:
                statusList = Stream.of("snStatus", "qcStatus", "printStatus").collect(Collectors.toList());
                for (String status : statusList) {
                    if (mapDiff.containsKey(status)){
                        isSave = true;
                    }
                }
                break;
            case MES_WORK_ORDER:
                statusList = Stream.of("workOrderStatus").collect(Collectors.toList());
                for (String status : statusList) {
                    if (mapDiff.containsKey(status)){
                        isSave = true;
                    }
                }
                break;
            case MES_SHIPPING_ORDER:
                statusList = Stream.of("status").collect(Collectors.toList());
                for (String status : statusList) {
                    if (mapDiff.containsKey(status)){
                        isSave = true;
                    }
                }
                break;
//            case MES_LOADING_LIST:
//                statusList = Stream.of("status").collect(Collectors.toList());
//                for (String status : statusList) {
//                    if (mapDiff.containsKey(status)){
//                        isSave = true;
//                    }
//                }
//                break;
            default:
        }
        if (!isSave && !isInsert) {
            LOGGER.info("状态相关字段没有变更，不需要进行记录");
            return;
        }
        // 是否需要落库
        if (reqJson.getString(afterMesPojoVersion.getRefClass()) != null) {
            List<String> fileds = Arrays.asList(reqJson.getString(afterMesPojoVersion.getRefClass()).split(","));
            mapDiff = mapDiff.entrySet().stream().filter(e -> fileds.contains(e.getKey())).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
        } else {
            mapDiff = null;
            LOGGER.info("没有变化的字段，不需要进行持久化");
            return;
        }


        String pojoCompare = mapDiff == null ? null : mapDiff.toString();

        versionNo = Objects.nonNull(beforePojoVersion) ? beforePojoVersion.getVersionNo() : 0;
        afterMesPojoVersion.setVersionNo(++versionNo);
        afterMesPojoVersion.setId(snowflakeIdMaker.nextId());


        afterPojoVersionDetail = new MesPojoVersionDetail();
        afterPojoVersionDetail.setId(snowflakeIdMaker.nextId());
        afterPojoVersionDetail.setPojoVersionId(afterMesPojoVersion.getId());

        afterPojoVersionDetail.setPojoBefore(JSON.toJSONString(beforeMap));
        afterPojoVersionDetail.setPojoAfter(JSON.toJSONString(afterMap));
        afterPojoVersionDetail.setPojoCompare(pojoCompare);

        afterPojoVersionDetail.setPojoBeforeTxt(getMapToStr(beforeMap, mapPropDesc));
        afterPojoVersionDetail.setPojoAfterTxt(getMapToStr(afterMap, mapPropDesc));
        afterPojoVersionDetail.setPojoCompareTxt(getMapDiffToStr(mapDiff, mapPropDesc));

        String name = afterMesPojoVersion.getCreateUser();
        String organizeCode = afterMesPojoVersion.getOrganizeCode();
        afterPojoVersionDetail.setOrganizeCode(organizeCode);
        ConvertBean.serviceModelInitialize(afterPojoVersionDetail, name);
        mesPojoVersionDetailRepository.insert(afterPojoVersionDetail);

        afterMesPojoVersion.setOperateType(operateType.getValue());
        afterMesPojoVersion.setVersionNo(versionNo);
        afterMesPojoVersion.setPojoCompare(pojoCompare);
        afterMesPojoVersion.setPojoCompareTxt(getMapDiffToStr(mapDiff, mapPropDesc));
        afterMesPojoVersion.setPojoDetailId(afterPojoVersionDetail.getId());
        ConvertBean.serviceModelInitialize(afterMesPojoVersion, name);
        mesPojoVersionRepository.insert(afterMesPojoVersion);
        LOGGER.info("保存的pojoVersion:{}",afterMesPojoVersion);

    }

    /**
     * Map数据转文本
     *
     * @param mapData
     * @param mapPropDesc
     * @return
     */
    private String getMapToStr(Map<String, Object> mapData, Map<String, String> mapPropDesc) {
        if (mapData == null) {
            mapData = new HashMap<>();
        }
        if (mapPropDesc == null) {
            mapData = new HashMap<>();
        }

        StringBuilder stringBuffer = new StringBuilder();
        String key;
        for (Map.Entry<String, Object> entry : mapData.entrySet()) {
            key = mapPropDesc.get(entry.getKey());
            if (key == null) {
                key = entry.getKey();
            }
            stringBuffer.append(key).append(":").append(entry.getValue()).append(",");
        }
        return stringBuffer.toString();
    }

    /**
     * MapDifference数据转文本
     *
     * @param mapData
     * @param mapPropDesc
     * @return
     */
    private String getMapDiffToStr(Map<String, MapDifference.ValueDifference<Object>> mapData, Map<String, String> mapPropDesc) {
        if (mapData == null) {
            mapData = new HashMap<>();
        }
        if (mapPropDesc == null) {
            mapData = new HashMap<>();
        }

        StringBuilder stringBuffer = new StringBuilder();
        String key;
        MapDifference.ValueDifference<Object> valDiff;
        for (Map.Entry<String, MapDifference.ValueDifference<Object>> entry : mapData.entrySet()) {
            valDiff = entry.getValue();
            if (valDiff == null) {
                continue;
            }
            key = mapPropDesc.get(entry.getKey());
            if (key == null) {
                key = entry.getKey();
            }
            stringBuffer.append("修改值 ").append(key)
                    .append("，旧值为 ").append(valDiff.leftValue())
                    .append("，新值为 ").append(valDiff.rightValue())
                    .append("。");
        }
        return stringBuffer.toString();
    }
}
