package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.collect;

import cn.estsh.i3plus.ext.mes.pcn.pojo.model.SxThirdPartyPlcCollectDataModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.api.iservice.busi.IShippingDispatchService;
import cn.estsh.i3plus.platform.common.util.MesPcnConstWords;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import org.springframework.util.StringUtils;

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

/**
 * 第三方PLC数据采集-监控处理器-生产数据
 */
public class SxThirdPartyPlcCollectProductDataHandler extends SxThirdPartyPlcCollectMonitorHandler {

    private Long startTime;

    private Long endTime;

    private StationRequestBean reqBean;

    private volatile SxThirdPartyPlcCollectDataModel plcCollectData;

    private IShippingDispatchService shippingDispatchService;

    public SxThirdPartyPlcCollectProductDataHandler(String org, String key) {
        super(org, key);
        shippingDispatchService = (IShippingDispatchService) SpringContextsUtil.getBean("shippingDispatchService");
    }

    @Override
    public SxThirdPartyPlcCollectProductDataHandler doRetry(Object obj) {

        super.doRetry(obj);

        if (isOpen) super.cancel();

        SxThirdPartyPlcCollectDataModel plcCollectData = (SxThirdPartyPlcCollectDataModel) obj;

        if (null == this.plcCollectData) this.plcCollectData = plcCollectData;
        else if (compareToRetry(plcCollectData)) isRetry = true;

        if (isRetry || null == filterChain) instanceFilterChain();

        restoreStepResultData();

        super.doSubmit();

        return this;
    }

    @Override
    public void execMonitor() {

        startTime = System.currentTimeMillis();

        while (isOpen) {

            endTime = System.currentTimeMillis();

            if (checkTimeOut()) return;

            if (null == filterChain) continue;

            stepResult = filterChain.exec(stepResult);

            if (!stepResult.isCompleted()) continue;

            doSendScanQueueNextExec();

            return;

        }

    }

    private Boolean compareToRetry(SxThirdPartyPlcCollectDataModel plcCollectData) {
        if (this.plcCollectData.getPlcCode2PlcFlag().equals(plcCollectData.getPlcCode2PlcFlag())
                && this.plcCollectData.getPlcCode2PcnFlag().equals(plcCollectData.getPlcCode2PcnFlag())
                && this.plcCollectData.getPlcCode2DataList().containsAll(plcCollectData.getPlcCode2DataList())
                && plcCollectData.getPlcCode2DataList().containsAll(this.plcCollectData.getPlcCode2DataList())) return false;
        this.plcCollectData = plcCollectData;
        return true;
    }

    private void instanceFilterChain() {
        filterChain = new SxThirdPartyPlcCollectStepFilterChain(org, key, MesPcnExtConstWords.PRODUCT_DATA)
                .clearField(getClearField()).sleepTime2UnComplete(500L)
                .add(new SxThirdPartyPlcCollectReadPlcStepService(plcCollectData.getPlcCode2PlcFlag()).targetValue(
                        new StringJoiner(MesPcnExtConstWords.COMMA).add(CommonEnumUtil.TRUE_OR_FALSE.TRUE.name().toLowerCase()).add(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr()).toString()))
                .add(new SxThirdPartyPlcCollectReadPlcStepService(plcCollectData.getPlcCode2PcnFlag()).targetValue(
                        new StringJoiner(MesPcnExtConstWords.COMMA).add(CommonEnumUtil.TRUE_OR_FALSE.FALSE.name().toLowerCase()).add(MesPcnExtConstWords.ZERO_STR).toString()));
        plcCollectData.getPlcCode2DataList().forEach(o -> filterChain.add(new SxThirdPartyPlcCollectReadPlcStepService(o)));
        filterChain.add(new SxThirdPartyPlcCollectWritePlcStepService(plcCollectData.getPlcCode2PcnFlag()).targetValue(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr()))
                .add(new SxThirdPartyPlcCollectProductDataStepService().targetField(plcCollectData.getPlcCode2DataList()));
        isRetry = false;
    }

    private void restoreStepResultData() {
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.USER_INFO);
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.SERIAL_NUMBER);
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.PRODUCT_SN);
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.MANAGE_CODE);
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.WORK_ORDER_NO);
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.PART_NO);
        ((Map<String, Object>) stepResult.getData()).remove(MesPcnExtConstWords.PART_NAME_RDD);
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.USER_INFO, plcCollectData.getUserInfo());
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.SERIAL_NUMBER, plcCollectData.getSerialNumber());
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.PRODUCT_SN, plcCollectData.getProductSn());
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.MANAGE_CODE, plcCollectData.getManageCode());
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.WORK_ORDER_NO, plcCollectData.getWorkOrderNo());
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.PART_NO, plcCollectData.getPartNo());
        ((Map<String, Object>) stepResult.getData()).put(MesPcnExtConstWords.PART_NAME_RDD, plcCollectData.getPartNameRdd());
    }

    private String[] getClearField() {
        List<String> clearFieldList = new ArrayList<>(plcCollectData.getPlcCode2DataList());
        clearFieldList.add(0, plcCollectData.getPlcCode2PlcFlag());
        clearFieldList.add(0, plcCollectData.getPlcCode2PcnFlag());
        return clearFieldList.toArray(new String[clearFieldList.size()]);
    }

    private Boolean checkTimeOut() {

        if (endTime - startTime < this.plcCollectData.getTimeOut()) return false;

        stepResult.msg(String.format("%s当前采集已超时!", StringUtils.isEmpty(stepResult.getMsg()) ? MesPcnExtConstWords.EMPTY : stepResult.getMsg()));

        doSendScanQueueNextExec();

        return true;

    }

    private void doSendScanQueueNextExec() {
        initStationRequestBean();
        reqBean.getDataMap().put(MesPcnExtConstWords.RESULT, stepResult.isCompleted());
        if (!StringUtils.isEmpty(stepResult.getMsg())) reqBean.getDataMap().put(MesPcnExtConstWords.INFO, stepResult.getMsg());
        shippingDispatchService.doSendScanQueueNextExec(reqBean);
    }

    private void initStationRequestBean() {
        if (null == reqBean) {
            reqBean = new StationRequestBean(plcCollectData.getOrganizeCode(), plcCollectData.getWorkCenterCode(), plcCollectData.getWorkCellCode());
            reqBean.setClientInfo(shippingDispatchService.getActorClientInfo(reqBean));
            reqBean.setTriggerAutoFsm(true);
            reqBean.setInterfaceType(MesPcnConstWords.SHIPPING);
            reqBean.setBusiType(MesPcnConstWords.WS_CMD_DO_SCAN);
        } else {
            reqBean.getDataMap().remove(MesPcnExtConstWords.RESULT);
            reqBean.getDataMap().remove(MesPcnExtConstWords.INFO);
        }

    }

}
