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

import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 第三方PLC数据采集-调度-单例模式
 */
@Slf4j
public class SxThirdPartyPlcCollectDispatchSingleton {

    protected volatile static Boolean isInit = false;

    private static class SxCellTaktDispatchHolder { private final static SxThirdPartyPlcCollectDispatchSingleton INSTANCE = new SxThirdPartyPlcCollectDispatchSingleton(); }

    public static SxThirdPartyPlcCollectDispatchSingleton getInstance() { return SxCellTaktDispatchHolder.INSTANCE; }

    private SxThirdPartyPlcCollectDispatchSingleton() { isInit = true; }

    private volatile static Map<String, SxThirdPartyPlcCollectMonitorHandler> monitorHandlerMap = new ConcurrentHashMap<>();

    public static Boolean getIsInit() { return isInit; }

    public static synchronized void execMonitor(String org, String busiCode, Map<String, Object> cfgMap, Boolean flag) {
        if (flag) {
            if (CollectionUtils.isEmpty(cfgMap)) execMonitorRemove(org, busiCode, getCellTaktMonitorMapKeyList(org, busiCode));
            else execMonitorCompareToCfg(org, busiCode, cfgMap);
        } else execMonitorCompute(org, busiCode, cfgMap);
    }

    private static void execMonitorRemove(String org, String busiCode, List<String> removeKeyList) {
        log.info("工厂{}第三方PLC数据采集 --- STRATEGY {} EXEC SINGLETON --- MONITOR CLOSED KEY: {} --- START ---", org, busiCode, CollectionUtils.isEmpty(removeKeyList) ? MesPcnExtConstWords.EMPTY : JSONObject.toJSONString(removeKeyList));
        if (!CollectionUtils.isEmpty(removeKeyList)) removeKeyList.stream().forEach(SxThirdPartyPlcCollectDispatchSingleton::execMonitorRemove);
    }

    private static void execMonitorCompareToCfg(String org, String busiCode, Map<String, Object> cfgMap) {
        List<String> cellTaktMonitorMapKeyList = getCellTaktMonitorMapKeyList(org, busiCode);
        List<String> removeKeyList = CollectionUtils.isEmpty(cellTaktMonitorMapKeyList) ? null : cellTaktMonitorMapKeyList.stream().filter(o -> (!StringUtils.isEmpty(o) && !cfgMap.containsKey(o))).collect(Collectors.toList());
        execMonitorRemove(org, busiCode, removeKeyList);
        execMonitorCompute(org, busiCode, cfgMap);
    }

    private static List<String> getCellTaktMonitorMapKeyList(String org, String busiCode) {
        List<String> cellTaktMonitorMapKeyList = CollectionUtils.isEmpty(monitorHandlerMap) ? null : new ArrayList<>(monitorHandlerMap.keySet());
        if (CollectionUtils.isEmpty(cellTaktMonitorMapKeyList)) return null;
        String suffix = new StringJoiner(MesPcnExtConstWords.COLON).add(busiCode).add(org).toString();
        return CollectionUtils.isEmpty(cellTaktMonitorMapKeyList) ? null : cellTaktMonitorMapKeyList.stream().filter(o -> (!StringUtils.isEmpty(o) && o.contains(suffix))).collect(Collectors.toList());
    }

    private static void execMonitorRemove(String key) {
        SxThirdPartyPlcCollectMonitorHandler handler = monitorHandlerMap.get(key);
        handler.cancel();
        monitorHandlerMap.remove(key);
        log.info("工厂{}第三方PLC数据采集 --- STRATEGY {} EXEC SINGLETON --- MONITOR CLOSED KEY: {} ---", key.split(MesPcnExtConstWords.COLON)[1], key.split(MesPcnExtConstWords.COLON)[0], key);
    }

    private static void execMonitorCompute(String org, String busiCode, Map<String, Object> cfgMap) {
        for (String key : cfgMap.keySet()) {
            if (StringUtils.isEmpty(key)) continue;
            SxThirdPartyPlcCollectMonitorHandler handler = monitorHandlerMap.computeIfAbsent(key, o -> instanceStrategyHandler(busiCode, org, key));
            if (null == handler) continue;
            handler.doRetry(cfgMap.get(key));
            log.info("工厂{}第三方PLC数据采集 --- STRATEGY {} EXEC SINGLETON --- MONITOR {} KEY: {} ---", org, busiCode, handler.version() ? "ADD" : "RETRY", key);
        }
    }

    private static SxThirdPartyPlcCollectMonitorHandler instanceStrategyHandler(String busiCode, String org, String key) {

        try {

            Class clazz = Class.forName(new StringJoiner(MesPcnExtConstWords.DECIMAL_POINT_UNESCAPE)
                    .add(SxThirdPartyPlcCollectDispatchSingleton.class.getPackage().getName()).add(MesPcnExtConstWords.SX_TPPC_SUFFIX + busiCode + MesPcnExtConstWords.HANDLER_SUFFIX).toString());

            Constructor constructor = clazz.getConstructor(String.class, String.class);

            return (SxThirdPartyPlcCollectMonitorHandler) constructor.newInstance(org, key);

        } catch (Exception e) {

            log.info("工厂{}第三方PLC数据采集 --- STRATEGY {} EXEC SINGLETON --- MONITOR ERROR KEY: {} --- INSTANCE STRATEGY HANDLER ERROR: {}  ---", org, busiCode, key, e.getMessage());

            return null;

        }

    }

}
