package org.ts.ddcs.Worker;


import com.alibaba.fastjson.JSONObject;
import org.ts.ddcs.Config.ServerConfig;
import org.ts.ddcs.DataTemplate.DataTemplateManager;
import org.ts.ddcs.DataTemplate.TemplateLineNode;
import org.ts.ddcs.Entity.CommandEntity;
import org.ts.ddcs.Log.LogHelper;
import org.ts.ddcs.RabbitMQ.RabbitQueueConfig;
import org.ts.ddcs.Service.*;
import org.ts.ddcs.mqtt.Mqtt;
import org.ts.ddcs.utils.GBConstants;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;


import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.concurrent.*;

@Component
@SuppressWarnings("all")
public class DataProcess {

    private ExecutorService dataSaveThreadPool = Executors.newFixedThreadPool(5);
    private ExecutorService dataGramThreadPool = Executors.newFixedThreadPool(5);
    private ExecutorService dataRelayManageThreadPool = Executors.newFixedThreadPool(1);
    private ExecutorService dataNotifyThreadPool = Executors.newFixedThreadPool(1);
    private ExecutorService dataGramRelayToRemoteThreadPool = Executors.newFixedThreadPool(3);
    private ExecutorService dataGramRetryThreadPool = Executors.newFixedThreadPool(1);
    private ExecutorService rtuStatusNotifyThreadPool = Executors.newFixedThreadPool(1);

    @Autowired
    public ServerConfig config;

//
//    @Value("${config.server.manage_managehost}")
//    public String managehost;
//
//    @Value("${config.server.manage_manageport}")
//    public int manageport;
//
//    @Value("${config.server.notifyurl}")
//    public String notifyurl;


    @Autowired
    public SwService swService;

    @Autowired
    public WqService wqService;

    @Autowired
    public RelayService relayService;

    @Autowired
    public RtuService rtuService;

    @Autowired
    public SzyService szyService;

    @Autowired
    public WarningService warningService;

//    @Autowired
//    public AmqpTemplate amqpTemplate;

    @Autowired
    public RabbitQueueConfig queueConfig;

    @Autowired
    public Mqtt mqttServer;

//    @Value("${config.server.relayRemote}")
//    public boolean relayRemote;
//
//    @Value("${config.server.dataBaseSave}")
//    public boolean dataBaseSave;
//
//    @Value("${config.server.correctValueUrl}")
//    public String correctValueUrl;
//
//    @Value("${config.server.releayStyle}")
//    public String releayStyle;
//
//    @Value("${config.server.connectManage}")
//    public boolean connectManage;
//
//    @Value("${config.server.rtuStatusCheck}")
//    public boolean rtuStatusCheck;
//
//    @Value("${config.server.relayToTaishan}")
//    public boolean relayToTaishan;
//
//    @Value("${config.server.itemtemplates}")
//    public String itemtemplates;
//
//    @Value("${config.server.templates}")
//    public String templates;

    @Autowired
    public JdbcTemplate jdbcTemplate;

    @Autowired
    public FastFileStorageClient fastFileStorageClient;

    @Autowired
    public RedisTemplate redisTemplate;

    @Autowired
    public KafkaTemplate kafkaTemplate;


    public static ServerConfig config() {
        return DataProcessHolder.newInstance().dataProcess.config;
    }

    public static RabbitQueueConfig queueConfig() {
        return DataProcessHolder.newInstance().dataProcess.queueConfig;
    }

    @PostConstruct
    public void init() {
        try {
            DataProcessHolder.newInstance().dataProcess = this;
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(new StringRedisSerializer());

            DataTemplateManager.newInstance().setItemTemplateConfig(DataProcess.config().getItemtemplates()).loadItemTemplateConfig();
            DataTemplateManager.newInstance().setTemplateConfig(DataProcess.config().getTemplates()).loadTemplateConfig();
//            if (DataProcess.config().isDataBaseSave()) {
//                LogHelper.info("数据库写入操作权限打开");
//            } else {
//                LogHelper.info("数据库写入操作权限关闭");
//            }
//            if (DataProcess.config().isRelayRemote()) {
//                LogHelper.info("报文转发到客户服务器权限打开");
//            } else {
//                LogHelper.info("报文转发到客户服务器权限关闭");
//            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitDataSaveTask(TemplateLineNode msg) {
        try {
            DataSaveProcess workertask = new DataSaveProcess(msg);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataSaveThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitSzy2012DataGramTask(String msg) {
        try {
            DataGramSzy2012Process workertask = new DataGramSzy2012Process(msg);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitSzy2012DataGramRelayTask(String rtuCode, Date collectTime, Date pickTime, String ip, String datagram) {
        try {
            DataGramSzy2012RelayProcess workertask = new DataGramSzy2012RelayProcess(rtuCode, collectTime, pickTime, ip, datagram);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramRelayToRemoteThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitXamSzy2012DataGramRelayTask(String rtuCode, Date collectTime, Date pickTime, String ip, String datagram) {
        try {
            DataGramXAMSzy2012RelayProcess workertask = new DataGramXAMSzy2012RelayProcess(rtuCode, collectTime, pickTime, ip, datagram);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramRelayToRemoteThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitDlSzy2012DataGramRelayTask(String rtuCode, Date collectTime, Date pickTime, String ip, String datagram) {
        try {
            DataGramDLSw2014RelayProcess workertask = new DataGramDLSw2014RelayProcess(rtuCode, collectTime, pickTime, ip, datagram);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramRelayToRemoteThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitSw2014DataGramRelayTask(String rtuCode, Date collectTime, Date pickTime, String ip, String datagram) {
        try {
            DataGramSw2014RelayProcess workertask = new DataGramSw2014RelayProcess(rtuCode, collectTime, pickTime, ip, datagram);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramRelayToRemoteThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitSzy2012SupplementDataGramTask(String datagram) {
        try {
            SupplementDataGramSzy2012Process workertask = new SupplementDataGramSzy2012Process(datagram);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitRtuStatusNotifyTask(Date pickDt, TemplateLineNode templateLineNode, String datagram) {
        try {
            RtuStatusInfoRelayProcess workertask = new RtuStatusInfoRelayProcess(pickDt, templateLineNode, datagram);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.rtuStatusNotifyThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }


    public void SubmitSw2014DataGramTask(String msg) {
        try {
            DataGramSw2014Process workertask = new DataGramSw2014Process(msg);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitDtu2021DataGramTask(String msg) {
        try {
            DataGramDtu2021Process workertask = new DataGramDtu2021Process(msg);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitConnectManageTask(String rtuCode, String serverId, Date dt) {
        try {
            DataConnectManageProcess workertask = new DataConnectManageProcess(rtuCode, serverId, dt);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataNotifyThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 转发消息到泰山系统
     *
     * @param rtuCode
     * @param dataInfo
     */
    public void SubmitRelayManageTask(String rtuCode, JSONObject dataInfo) {
        try {
            DataRelayToManageProcess workertask = new DataRelayToManageProcess(rtuCode, dataInfo);
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataRelayManageThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public void SubmitRetryCheckTask() {
        try {
//            try {
//                Date dt = new Date();
//                DataProcessHolder.newInstance().dataProcess.amqpTemplate.convertAndSend("", new Long(dt.getTime()).toString());
//            } catch (Exception e) {
//                LogHelper.error(e);
//            }
            DataCommandRetryProcess workertask = new DataCommandRetryProcess();
            FutureTask<Integer> futureTask = new FutureTask<>(workertask);
            this.dataGramRetryThreadPool.submit(futureTask);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 清空指令0
     *
     * @param rtuCode
     */
    public static void ClearCommand(String rtuCode, String key) {
        try {
            if (null != rtuCode && null != key) {
                RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
                ListOperations<String, String> opsList = redisTemplate.opsForList();
                if (redisTemplate.hasKey(rtuCode + ":" + key)) {
                    if (redisTemplate.delete(rtuCode + ":" + key)) {
                        LogHelper.info(rtuCode + ": command clear : clear!");
                    }
                }
                HashOperations<String, String, String> ops = redisTemplate.opsForHash();
                if (ops.hasKey(rtuCode, key)) {
                    ops.delete(rtuCode, key);
                }
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 指令回报
     *
     * @param rtuCode
     * @param funcCode
     */
    public static void CommandComplete(String rtuCode, String funcCode) {
        try {
            if (null != rtuCode) {
                RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
                HashOperations<String, String, String> ops = redisTemplate.opsForHash();
                if (ops.hasKey(rtuCode, GBConstants.REDIS_KEY_COMMAND_FILE)) {
                    String commandJson = ops.get(rtuCode, GBConstants.REDIS_KEY_COMMAND_FILE);
                    JSONObject command = JSONObject.parseObject(commandJson);
                    boolean isTry = command.getBoolean("try");
                    if (isTry) {
                        String commandfuncCode = command.getString("funcCode");
                        if (commandfuncCode.equals(funcCode)) {
                            ops.delete(rtuCode, GBConstants.REDIS_KEY_COMMAND_FILE);
                            return;
                        } else {
                            long tryCount = command.getLong("tryCount");
                            if (tryCount >= 10) {
                                ops.delete(rtuCode, GBConstants.REDIS_KEY_COMMAND_FILE);
                                if (redisTemplate.delete(rtuCode + ":" + GBConstants.REDIS_KEY_COMMAND_FILE)) {
                                    LogHelper.info(rtuCode + ": command clear : file down fail !!  clear  !");
                                }
                            }
                        }
                    }
                }

                if (ops.hasKey(rtuCode, GBConstants.REDIS_KEY_COMMAND_SETTING)) {
                    String commandJson = ops.get(rtuCode, GBConstants.REDIS_KEY_COMMAND_SETTING);
                    LogHelper.info(rtuCode + ": command complete:  " + commandJson);
                    JSONObject command = JSONObject.parseObject(commandJson);
                    boolean isTry = command.getBoolean("try");
                    if (isTry) {
                        String commandfuncCode = command.getString("funcCode");
                        if (commandfuncCode.equals(funcCode)) {
                            ops.delete(rtuCode, GBConstants.REDIS_KEY_COMMAND_SETTING);
                            return;
                        }
                    }
                }

                if (ops.hasKey(rtuCode, GBConstants.REDIS_KEY_COMMAND_QUERY)) {
                    String commandJson = ops.get(rtuCode, GBConstants.REDIS_KEY_COMMAND_QUERY);
                    LogHelper.info(rtuCode + ": command complete:  " + commandJson);
                    JSONObject command = JSONObject.parseObject(commandJson);
                    boolean isTry = command.getBoolean("try");
                    if (isTry) {
                        String commandfuncCode = command.getString("funcCode");
                        if (commandfuncCode.equals(funcCode)) {
                            ops.delete(rtuCode, GBConstants.REDIS_KEY_COMMAND_QUERY);
                            return;
                        }
                    }
                }
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 下行指令任务
     *
     * @param rtuCode
     * @param datagram
     */
    public static void SubmitCommand(String rtuCode, String datagram, String funcCode) {
        try {
            CommandEntity entity = new CommandEntity();
            entity.setDatagram(datagram);
            entity.setRtuCode(rtuCode);
            entity.setNeedTry(false);
            entity.setTryCount(0);
            entity.setCreateTime(new Date());
            entity.setLiveTime(24 * 60);
            entity.setFuncCode(funcCode);
            entity.setWaittingBack(true);
            entity.setTry(false);

            RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
            ListOperations<String, String> opsList = redisTemplate.opsForList();
            String commandJsonStr = JSONObject.toJSONString(entity);
            LogHelper.info("query command :" + commandJsonStr);
            opsList.rightPush(entity.getRtuCode() + ":" + GBConstants.REDIS_KEY_COMMAND_QUERY, commandJsonStr);

        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 下行指令任务
     *
     * @param commandEntity
     */
    public static void SubmitFileCommand(CommandEntity commandEntity) {
        try {
            if (null != commandEntity) {
                RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
                ListOperations<String, String> opsList = redisTemplate.opsForList();
                String commandJsonStr = JSONObject.toJSONString(commandEntity);
                LogHelper.info("file command :" + commandJsonStr);
                opsList.rightPush(commandEntity.getRtuCode() + ":" + GBConstants.REDIS_KEY_COMMAND_FILE, commandJsonStr);
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 下行指令任务,指定优先级
     *
     * @param rtuCode
     * @param datagram
     * @param isSetting
     */
    public static void SubmitCommand(String rtuCode, String datagram, String funcCode, boolean isSetting) {
        try {
            if (isSetting) {
                CommandEntity entity = new CommandEntity();
                entity.setDatagram(datagram);
                entity.setRtuCode(rtuCode);
                entity.setNeedTry(false);
                entity.setTryCount(0);
                entity.setCreateTime(new Date());
                entity.setLiveTime(24 * 60);
                entity.setFuncCode(funcCode);
                entity.setWaittingBack(true);
                entity.setTry(false);

                RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
                ListOperations<String, String> opsList = redisTemplate.opsForList();
                String commandJsonStr = JSONObject.toJSONString(entity);
                LogHelper.info("setting command :" + commandJsonStr);
                opsList.rightPush(entity.getRtuCode() + ":" + GBConstants.REDIS_KEY_COMMAND_SETTING, commandJsonStr);
            } else {
                DataProcess.SubmitCommand(rtuCode, datagram, funcCode);
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    /**
     * 通知转发下行指令
     *
     * @param rtuCode
     * @param datagram
     */
    public void SubmitDownCommandNotifyTask(String rtuCode) {
        try {
            if (null != rtuCode) {
                DataNotifyProcess workertask = new DataNotifyProcess(rtuCode);
                FutureTask<Integer> futureTask = new FutureTask<>(workertask);
                this.dataNotifyThreadPool.submit(workertask);
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }

    public static void DownloadNotify(String rtuCode) {
        try {
            if (null != rtuCode) {
                DataProcessHolder.newInstance().dataProcess.SubmitDownCommandNotifyTask(rtuCode);
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }


    public static void MQNotifyMsgSender(String masterId, String body) {
        try {
            String datagramDownToRtu = DataProcessHolder.newInstance().dataProcess.queueConfig.getToRtuDatagram();
            DataProcessHolder.newInstance().dataProcess.kafkaTemplate.send(datagramDownToRtu , body);
        } catch (Exception e) {
            LogHelper.error(e);
        }
    }
}
