package io.wdd.agent.executor;

import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import io.wdd.agent.config.utils.AgentCommonThreadPool;
import io.wdd.agent.executor.config.ExecutorFunctionNacosCollector;
import io.wdd.common.beans.executor.ExecutionMessage;
import io.wdd.common.beans.rabbitmq.OctopusMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executor;

import static io.wdd.agent.executor.config.ExecutorFunctionNacosCollector.ALL_FUNCTION_MAP;
import static io.wdd.agent.executor.config.ExecutorFunctionNacosCollector.NacosConfigService;

@Service
@Slf4j
public class FunctionExecutor {

    @Resource
    CommandExecutor commandExecutor;

    // todo called by timer
    @Resource
    ExecutorFunctionNacosCollector executorFunctionNacosCollector;


    public void execute(OctopusMessage octopusMessage, ExecutionMessage executionMessage, boolean isScheduledScript) {

        // 拿到 resultKey
        String resultKey = executionMessage.getResultKey();

        List<List<String>> multiLineCommand;
        if (isScheduledScript) {
            // 检测到是 页面定时任务脚本
            multiLineCommand = executionMessage.getMultiLineCommand();
        } else {
            // 从 ALL_FUNCTION_MAP本地容器中(Nacos配置中获取)获取到 功能脚本的内容
            multiLineCommand = ALL_FUNCTION_MAP.get(executionMessage.getType());
        }

        // 防止阻塞消息队列中的其他信息，需要使用异步执行
        AgentCommonThreadPool.pool.submit(
                () -> this.doExecuteFunction(
                        resultKey,
                        multiLineCommand,
                        executionMessage.isNeedResultReplay(),
                        executionMessage.isDurationTask(),
                        octopusMessage
                )
        );

    }


    private void doExecuteFunction(String streamKey, List<List<String>> multiLineCommand, boolean needResultReplay, boolean durationTask, OctopusMessage octopusMessage) {

        log.info(
                "[ Function Executor ] all commands are ==> {}",
                multiLineCommand
        );

        Iterator<List<String>> iterator = multiLineCommand.iterator();

        // 此处的策略为，将所有的命令是为一个整体，必须完整执行才可，完整返回结果
        while (iterator.hasNext()) {
            int execute = commandExecutor.execute(
                    streamKey,
                    iterator.next(),
                    needResultReplay,
                    durationTask,
                    octopusMessage
            );

            if (execute != 0) {
                log.error("command list execute failed !");
                break;
            }
        }

    }


    /**
     * 后台监听Nacos的配置，实时跟新从Nacos中修改过的 函数命令脚本的内容
     */
    @Bean
    private void daemonListenToNacosFunctions() {

        // add listener to listen to the real-time change of the Function Shell Scripts
        try {
            NacosConfigService.addListener(
                    executorFunctionNacosCollector.executorFunctionDataId + "." + executorFunctionNacosCollector.fileExtension,
                    executorFunctionNacosCollector.group,
                    new Listener() {
                        @Override
                        public Executor getExecutor() {
                            return null;
                        }

                        @Override
                        public void receiveConfigInfo(String s) {

                            log.info(
                                    "detected nacos function shell update ! {}",
                                    s
                            );

                            // 解析获取到的功能脚本的字符串，然后解析为缓存
                            executorFunctionNacosCollector.parseNacosFunctionYamlToMap(s);
                        }
                    }
            );

        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

}
