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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesEquipmentLogService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesEquipmentLogExtService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesEquipVariableCollectContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.ActorMessage;
import cn.estsh.i3plus.ext.mes.pcn.pojo.mqtt.EquipLogMqttMsg;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
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.MesEquipmentLog;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentLogDetail;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentRecord;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentVariable;
import cn.estsh.i3plus.pojo.mes.repository.MesEquipmentRecordRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesEquipmentVariableRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MesEquipmentLogService implements IMesEquipmentLogService {

    public static final Logger LOGGER = LoggerFactory.getLogger(CommonConstWords.SYSTEM_LOG);

    @Autowired
    private MesEquipmentVariableRepository equipmentVariableRepository;

    @Autowired
    private IMesEquipmentLogExtService equipmentLogExtService;

    @Autowired
    private MesEquipmentExtService equipmentExtService;

    @Autowired
    private MesEquipmentRecordRepository mesEquipmentRecordRepository;

    @Autowired
    private SnowflakeIdMaker snowflakeIdMaker;

    @Resource(name = "redisMesPcn")
    private ImppRedis redisMesPcn;

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void saveEquipmentLogToRedis(ActorMessage actorMessage) {
        // 获取设备变量属性
        List<MesEquipmentVariable> equipmentVariableList = equipmentExtService.getEquipmentVariableList(actorMessage.getOrganizeCode(), actorMessage.getEquipmentCode(), MesExtEnumUtil.EQUIP_VARIABLE_TYPE.PROCESS_FINISH.getValue());
        // 获取变量ID集合
        Map<Long, MesEquipmentVariable> equipVariableMap = CollectionUtils.isEmpty(equipmentVariableList) ? null : equipmentVariableList.stream().filter(o -> null != o).collect(Collectors.toMap(MesEquipmentVariable::getId, o -> o));
        if (CollectionUtils.isEmpty(equipVariableMap)) {
            log.info("工厂{}生产线{}工位{}:FSM STATE DISPATCHER --- DO STEP --- {} EXEC --- 获取工艺参数未查询到工艺参数完成类型的设备数据变量", actorMessage.getOrganizeCode(), actorMessage.getWorkCenterCode(), actorMessage.getWorkCellCode(), "mesVariableWhenFinishedReadStepService");
            return;
        }

        // 获取设备数据采集信息
        List<MesEquipVariableCollectContext> equipmentLogList = equipmentLogExtService.getEquipmentLogCollectList(actorMessage.getOrganizeCode(), actorMessage.getEquipId(), MesExtEnumUtil.EQUIP_VARIABLE_NEED_NEW_VALUE.FALSE.getValue(), MesExtEnumUtil.EQUIP_VARIABLE_TYPE.PROCESS_FINISH.getValue());
        // 筛选出该设备中设备变量属性对应的数据采集信息
        equipmentLogList = CollectionUtils.isEmpty(equipmentLogList) ? null : equipmentLogList.stream().filter(o -> equipVariableMap.containsKey(o.getEquipVariableId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(equipmentLogList)) {
            log.info("工厂{}生产线{}工位{}:FSM STATE DISPATCHER --- DO STEP --- {} EXEC --- 获取工艺参数未查询到设备LOG", actorMessage.getOrganizeCode(), actorMessage.getWorkCenterCode(), actorMessage.getWorkCellCode(), "mesVariableWhenFinishedReadStepService");
            return;
        }

        equipmentLogList.forEach(o -> BeanUtils.copyProperties(equipVariableMap.get(o.getEquipVariableId()), o));

        MesEquipmentRecord mesEquipmentRecord =new MesEquipmentRecord();
        BeanUtils.copyProperties(actorMessage, mesEquipmentRecord);
        mesEquipmentRecord.setRecordStatus(MesExtEnumUtil.RECORD_STATUS.RECORD_STATUS_10.getValue());
        mesEquipmentRecord.setId(!StringUtils.isEmpty(actorMessage.getMouldRecordId()) ? actorMessage.getMouldRecordId() : snowflakeIdMaker.nextId());
        ConvertBean.serviceModelInitialize(mesEquipmentRecord, actorMessage.getUserName());

        String key = getKey(mesEquipmentRecord);
        equipmentLogList.forEach(equipLog -> redisMesPcn.putList(key, equipLog));

        //不能使用insert, 防止id偶发重复问题
        mesEquipmentRecordRepository.save(mesEquipmentRecord);

        log.info("工厂{}生产线{}工位{}:FSM STATE DISPATCHER --- DO STEP --- {} EXEC --- KEY:{} --- 工艺参数:{}",
                actorMessage.getOrganizeCode(), actorMessage.getWorkCenterCode(), actorMessage.getWorkCellCode(), "mesVariableWhenFinishedReadStepService", key, JSONObject.toJSONString(equipmentLogList));

    }

    private String getKey(MesEquipmentRecord mesEquipmentRecord){
        return new StringJoiner(MesPcnExtConstWords.COLON).add(mesEquipmentRecord.getOrganizeCode()).add(mesEquipmentRecord.getWorkCenterCode()).add(mesEquipmentRecord.getWorkCellCode()).add(mesEquipmentRecord.getEquipmentCode()).add(mesEquipmentRecord.getId().toString()).toString();
    }

    private String getVariableKey(String equipId, String keyType){
        return "PCN" + ":"+ keyType + ":" + equipId;
    }

    @Override
    public void saveEquipmentLogDetails(String organizeCode, String userInfo, Integer qty) {

        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.RECORD_STATUS.RECORD_STATUS_10.getValue(), MesPcnExtConstWords.RECORD_STATUS, ddlPackBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.ASC.getValue()}, new String[]{MesPcnExtConstWords.CREATE_DATE_TIME}, ddlPackBean);
        List<MesEquipmentRecord> mesEquipmentRecords = mesEquipmentRecordRepository.findByHqlTopWhere(ddlPackBean, 10);

        LOGGER.info("保存工艺参数JOB --- 读取到设备记录信息[{}]条 ---", CollectionUtils.isEmpty(mesEquipmentRecords) ? MesPcnExtConstWords.ZERO : mesEquipmentRecords.size());

        if (CollectionUtils.isEmpty(mesEquipmentRecords)) return;

        for (MesEquipmentRecord mesEquipmentRecord : mesEquipmentRecords) {
            if (null == mesEquipmentRecord) continue;
            saveEquipmentLogDetail(organizeCode, userInfo, qty, mesEquipmentRecord);
        }

    }

    private void saveEquipmentLogDetail(String organizeCode, String userInfo, Integer qty, MesEquipmentRecord mesEquipmentRecord) {

        String key = getKey(mesEquipmentRecord);
        List<MesEquipVariableCollectContext> equipmentLogList = (List<MesEquipVariableCollectContext>) redisMesPcn.getList(key, 0, -1);

        // 修改状态
        mesEquipmentRecord.setRecordStatus(CollectionUtils.isEmpty(equipmentLogList) ? MesExtEnumUtil.RECORD_STATUS.RECORD_STATUS_20.getValue() : MesExtEnumUtil.RECORD_STATUS.RECORD_STATUS_30.getValue());
        ConvertBean.serviceModelUpdate(mesEquipmentRecord, userInfo);
        mesEquipmentRecordRepository.save(mesEquipmentRecord);
        // 删除key
        redisMesPcn.deleteKey(key);

        if (CollectionUtils.isEmpty(equipmentLogList)) return;

        Optional<MesEquipVariableCollectContext> optional = equipmentLogList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getEquipId()))).findFirst();
        if (null == optional || !optional.isPresent()) return;


        insertBatchEquipmentLogDetail(organizeCode, optional.get().getEquipId(), userInfo, qty, mesEquipmentRecord, equipmentLogList);

    }

    private void insertBatchEquipmentLogDetail(String organizeCode, Integer equipId, String userInfo, Integer qty, MesEquipmentRecord mesEquipmentRecord, List<MesEquipVariableCollectContext> equipmentLogList) {

        if (CollectionUtils.isEmpty(equipmentLogList)) return;

        if (qty.compareTo(equipmentLogList.size()) >= 0) {
            equipmentLogExtService.insertBatchEquipmentLogDetail(organizeCode, equipId, userInfo, mesEquipmentRecord, equipmentLogList);
            return;
        } else {
            List<MesEquipVariableCollectContext> handleList = equipmentLogList.subList(0, qty);
            equipmentLogExtService.insertBatchEquipmentLogDetail(organizeCode, equipId, userInfo, mesEquipmentRecord, handleList);
            insertBatchEquipmentLogDetail(organizeCode, equipId, userInfo, qty, mesEquipmentRecord, equipmentLogList.subList(qty, equipmentLogList.size()));
        }
    }

    @Override
    public void updateValue(EquipLogMqttMsg equipLogMqttMsg) {

        log.info("== equipLogMqttMsg ==> messageArrived ，异步处理开始 消息内容: {}", equipLogMqttMsg);

        /**
         * 获取点位信息
         */
        MesEquipmentVariable mesEquipmentVariable = getMesEquipmentVariable(equipLogMqttMsg);
        if (mesEquipmentVariable == null) {
            return;
        }
        // 获取设备点位数据 //TODO 暂不使用此代码块 使用需要调整代码 此表已不支持shardingsphere配置
        MesEquipmentLog equipmentLog = getMesEquipmentLog(equipLogMqttMsg, mesEquipmentVariable);
        if (equipmentLog == null) {
            return;
        }
        // 更新设备点位数据  //TODO 暂不使用此代码块 使用需要调整代码 此表已不支持shardingsphere配置
        updateEquipmentLog(equipLogMqttMsg, mesEquipmentVariable, equipmentLog);


        MesEquipmentLogDetail mesEquipmentLogDetail = new MesEquipmentLogDetail();
        BeanUtils.copyProperties(equipmentLog, mesEquipmentLogDetail);
        ConvertBean.serviceModelInitialize(mesEquipmentLogDetail, "mqtt");
        mesEquipmentLogDetail.setEquipVariableValue(equipLogMqttMsg.getValue());
        log.info("== mesEquipmentLogDetail新增开始");
        saveLogDetail(mesEquipmentLogDetail);
        //mesEquipmentLogDetailRepository.insert(mesEquipmentLogDetail);
        log.info("== mesEquipmentLogDetail新增结束");
        log.info("== equipLogMqttMsg ==> messageArrived ，异步处理结束 消息内容: {}", equipLogMqttMsg);

    }

    private void updateEquipmentLog(EquipLogMqttMsg equipLogMqttMsg, MesEquipmentVariable mesEquipmentVariable, MesEquipmentLog equipmentLog) {
//        DdlPackBean packBean = DdlPackBean.getDdlPackBean(mesEquipmentVariable.getOrganizeCode());
//        DdlPreparedPack.getNumEqualPack(equipmentLog.getEquipId(), MesPcnExtConstWords.EQUIP_ID, packBean);
//        DdlPreparedPack.getNumEqualPack(equipmentLog.getEquipVariableId(), MesPcnExtConstWords.EQUIP_VARIABLE_ID, packBean);
//        log.info("== MesEquipmentLog修改开始");
//        mesEquipmentLogRepository.updateByProperties(new String[]{MesPcnExtConstWords.EQUIP_VARIABLE_STATUS,"equipVariableValue"}, new Object[]{MesExtEnumUtil.EQUIP_VARIABLE_NEED_NEW_VALUE.TRUE.getValue(), equipLogMqttMsg.getValue() }, packBean);
//        log.info("== MesEquipmentLog修改结束");
    }

    private MesEquipmentVariable getMesEquipmentVariable(EquipLogMqttMsg equipLogMqttMsg) {
        String variableKey = getVariableKey(equipLogMqttMsg.getPTCode(), "MES_EQUIPMENT_VARIABLE");
        Object obj = redisMesPcn.getHash(variableKey, equipLogMqttMsg.getKey());
        MesEquipmentVariable mesEquipmentVariable = new MesEquipmentVariable();
        if (obj == null) {
            log.info("== mesEquipmentVariable查询开始");
            DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean();
            DdlPreparedPack.getStringEqualPack(equipLogMqttMsg.getKey(), "tagName", ddlPackBean);
            DdlPreparedPack.getNumEqualPack(Integer.valueOf(equipLogMqttMsg.getPTCode()), "equipId", ddlPackBean);
            mesEquipmentVariable = equipmentVariableRepository.getByProperty(ddlPackBean);
            log.info("== mesEquipmentVariable查询结束");
            if (mesEquipmentVariable == null) {
                LOGGER.info("tagAddress 不存在【{}】", equipLogMqttMsg.getTagAddress());
                return null;
            }
            redisMesPcn.putHash(variableKey, equipLogMqttMsg.getKey(), mesEquipmentVariable);
        } else {
            mesEquipmentVariable = (MesEquipmentVariable) obj;
        }

        return mesEquipmentVariable;
    }

    private MesEquipmentLog getMesEquipmentLog(EquipLogMqttMsg equipLogMqttMsg, MesEquipmentVariable mesEquipmentVariable) {
//        String variableKey = getVariableKey(equipLogMqttMsg.getPTCode(), "MES_EQUIPMENT_LOG");
//        Object obj = redisMesPcn.getHash(variableKey, equipLogMqttMsg.getKey());
//        MesEquipmentLog equipmentLog  = new MesEquipmentLog();
//        if (obj == null) {
//            log.info("== MesEquipmentLog查询开始");
//            equipmentLog = mesEquipmentLogExtService.queryMesEquipmentLog(mesEquipmentVariable.getOrganizeCode(), Integer.valueOf(equipLogMqttMsg.getPTCode()), mesEquipmentVariable.getId());
//            log.info("== MesEquipmentLog查询结束");
//            if (equipmentLog == null) {
//                LOGGER.info("log信息不存在 不存在【{}】", equipLogMqttMsg.getTagAddress());
//                return null;
//            }
//            redisMesPcn.putHash(variableKey, equipLogMqttMsg.getKey(), equipmentLog);
//        } else {
//            equipmentLog = (MesEquipmentLog) obj;
//        }
//        return equipmentLog;
        return null;
    }

    public void saveLogDetail(MesEquipmentLogDetail mesEquipmentLogDetail) {
        Long id = snowflakeIdMaker.nextId();
        String sql = getSql(mesEquipmentLogDetail.getEquipId());

        Query query = entityManager.createNativeQuery(sql);
        query.setParameter("organize_code", mesEquipmentLogDetail.getOrganizeCode());
        query.setParameter("is_valid", CommonEnumUtil.IS_VAILD.VAILD.getValue());
        query.setParameter("is_deleted", CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        query.setParameter("id", id);
        query.setParameter("equip_variable_id", mesEquipmentLogDetail.getEquipVariableId());
        query.setParameter("equip_variable_name", mesEquipmentLogDetail.getEquipVariableName());
        query.setParameter("equip_variable_desc", mesEquipmentLogDetail.getEquipVariableDesc());
        query.setParameter("read_write_flag", mesEquipmentLogDetail.getReadWriteFlag());
        query.setParameter("data_type", mesEquipmentLogDetail.getDataType());
        query.setParameter("equip_variable_value", mesEquipmentLogDetail.getEquipVariableValue());
        query.setParameter("equip_id", mesEquipmentLogDetail.getEquipId());
        query.setParameter("equipment_code", mesEquipmentLogDetail.getEquipmentCode());
        query.setParameter("work_center_code", mesEquipmentLogDetail.getWorkCenterCode());
        query.setParameter("work_cell_code", mesEquipmentLogDetail.getWorkCellCode());
        query.setParameter("process_code", mesEquipmentLogDetail.getProcessCode());
        query.setParameter("craft_code", mesEquipmentLogDetail.getCraftCode());
        query.setParameter("mould_record_id", mesEquipmentLogDetail.getMouldRecordId());
        query.setParameter("extend", mesEquipmentLogDetail.getExtend());
        query.setParameter("quality", mesEquipmentLogDetail.getQuality());
        query.setParameter("create_date_time", mesEquipmentLogDetail.getCreateDatetime());
        query.setParameter("create_user", mesEquipmentLogDetail.getCreateUser());
        query.setParameter("is_deleted", mesEquipmentLogDetail.getIsDeleted());
        query.setParameter("is_valid", mesEquipmentLogDetail.getIsValid());
        query.setParameter("modify_date_time", mesEquipmentLogDetail.getCreateDatetime());
        query.setParameter("organize_code", mesEquipmentLogDetail.getOrganizeCode());
        query.setParameter("modify_user", mesEquipmentLogDetail.getModifyUser());
        query.setParameter("system_sync_status", mesEquipmentLogDetail.getSystemSyncStatus());
        query.setParameter("remark", mesEquipmentLogDetail.getRemark());
        query.setParameter("description", mesEquipmentLogDetail.getDescription());
        query.setParameter("system_sync_date_time", mesEquipmentLogDetail.getSystemSyncDatetime());

        query.executeUpdate();

    }

    private String getSql(Integer equipId) {
      //  String sql = "insert INTO mes_equipment_log_detail_" + equipId +
                String sql = "insert INTO mes_equipment_log_detail"  +

                "( id, equip_variable_id, equip_variable_name, equip_variable_desc, read_write_flag, data_type, equip_variable_value," +
                " equip_id, equipment_code, work_center_code, work_cell_code, process_code, craft_code, mould_record_id, extend, quality, " +
                "create_date_time, create_user, is_deleted, is_valid, modify_date_time, modify_user, organize_code, system_sync_status, remark," +
                " description, system_sync_date_time) VALUES " +
                "(:id, :equip_variable_id, :equip_variable_name, :equip_variable_desc, :read_write_flag, :data_type, :equip_variable_value, :equip_id, :equipment_code, " +
                ":work_center_code, :work_cell_code, :process_code, :craft_code, " +
                ":mould_record_id, :extend, :quality, :create_date_time, :create_user, :is_deleted, :is_valid, :modify_date_time, :modify_user" +
                ", :organize_code, :system_sync_status, :remark, :description, :system_sync_date_time)";
        return sql;
    }
}
