package io.wdd.rpc.execute.service;

import io.wdd.common.utils.TimeUtils;
import io.wdd.rpc.execute.ExecutionMessage;
import io.wdd.rpc.message.OctopusMessage;
import io.wdd.rpc.message.OctopusMessageType;
import io.wdd.rpc.message.handler.OMessageReplayContent;
import io.wdd.rpc.message.sender.OMessageToAgentSender;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static io.wdd.rpc.message.handler.OMessageHandler.*;
import static io.wdd.rpc.status.AllAgentStatusCache.ALL_AGENT_TOPIC_NAME_SET;

@Service
@Slf4j
public class ExecutionServiceImpl implements ExecutionService {

    private static final String MANUAL_COMMAND_TYPE = "manual-command";

    private static final int COMMAND_MAX_WAIT_TIMEOUT = 120;

    @Resource
    OMessageToAgentSender oMessageToAgentSender;

    @Override
    public ArrayList<String> SendCommandToAgent(String agentTopicName, String executionType, List<String> funcContent, List<List<String>> pipeLineCommand, List<String> commandList, List<List<String>> commandListComplete, boolean needResultReplay, boolean durationTask) {

        ArrayList<String> commandResultLog = null;

        if (!validateCommandInfo(agentTopicName)) {
            return commandResultLog;
        }

        // 归一化type
        if (StringUtils.isEmpty(executionType)) {
            executionType = MANUAL_COMMAND_TYPE;
        }

        // 构造 Execution Command对应的消息体
        ExecutionMessage executionMessage = this
                .generateExecutionMessage(
                        executionType,
                        funcContent,
                        pipeLineCommand,
                        commandList,
                        commandListComplete,
                        needResultReplay,
                        durationTask
                );
        OctopusMessage octopusMessage = this.generateOctopusMessage(
                agentTopicName,
                executionMessage
        );

        // send the message
        oMessageToAgentSender.send(octopusMessage);

        // debug
        log.debug(
                "发送的 matchKey为 {}, 内容为 {}",
                GenerateOMessageMatchKey(
                        octopusMessage.getOctopusMessageType(),
                        octopusMessage.getInit_time()
                ),
                octopusMessage
        );

        // 需要返回结果

        // 超时等待时间，默认为 COMMAND_MAX_WAIT_TIMEOUT
        int commandMaxWaitTimeout = COMMAND_MAX_WAIT_TIMEOUT;
        if (durationTask) {
            // 2023年11月9日 超长的任务时间设置为5分钟
            commandMaxWaitTimeout = COMMAND_MAX_WAIT_TIMEOUT * 5;
        }
        // 等待结果
        // countDownLatch的个数约定为1, agent会合并多行命令的结果一并返回
        OMessageReplayContent replayContent = WaitFromAgent(
                octopusMessage,
                1
        );

        CountDownLatch replayLatch = replayContent.getCountDownLatch();
        boolean waitOK = false;

        try {

            // 2023年10月8日 根据执行的命令数量设定超时等待时间
            if (!CollectionUtils.isEmpty(commandListComplete)) {
                commandMaxWaitTimeout = COMMAND_MAX_WAIT_TIMEOUT * commandListComplete.size();
            }

            waitOK = replayLatch.await(
                    commandMaxWaitTimeout,
                    TimeUnit.SECONDS
            );

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {

            // 释放等待队列
            StopWaitingResult(octopusMessage);

            // 转换结果
            commandResultLog = (ArrayList<String>) octopusMessage.getResult();


            Object executionContent;
            if (executionMessage
                    .getExecutionType()
                    .equals("BASE")) {
                executionContent = executionMessage.getExecutionType() + "==" + executionMessage.getFuncContent();
            } else if (executionMessage.getSingleLineCommand() != null) {
                executionContent = executionMessage.getSingleLineCommand();
            } else {
                executionContent = executionMessage.getMultiLineCommand();
            }

            // debug
            log.debug(
                    "执行命令 {}  {} 在规定时间内结束， 结果为 {} 返回内容为 {}",
                    executionContent,
                    waitOK ? "已经" : "未",
                    octopusMessage.getResultCode(),
                    commandResultLog
            );

        }


        return commandResultLog;
    }


    private OctopusMessage generateOctopusMessage(String agentTopicName, ExecutionMessage executionMessage) {

        return OctopusMessage
                .builder()
                .octopusMessageType(OctopusMessageType.EXECUTOR)
                .init_time(TimeUtils.currentFormatTime())
                .uuid(agentTopicName)
                .content(
                        executionMessage
                )
                .build();
    }

    private ExecutionMessage generateExecutionMessage(String executionType, List<String> funcContent, List<List<String>> pipeLineCommand, List<String> commandList, List<List<String>> commandListComplete, boolean needResultReplay, boolean durationTask) {

        return ExecutionMessage
                .builder()
                .executionType(executionType)
                .funcContent(funcContent)
                .singleLineCommand(commandList)
                .multiLineCommand(commandListComplete)
                .pipeLineCommand(pipeLineCommand)
                .needResultReplay(needResultReplay)
                .durationTask(durationTask)
                .build();
    }


    private boolean validateCommandInfo(String agentTopicName) {

        // todo remove
        ALL_AGENT_TOPIC_NAME_SET.add("Chengdu-amd64-99-3b1609");

        // 检查agentTopicName是否存在
        if (!ALL_AGENT_TOPIC_NAME_SET.contains(agentTopicName)) {
            log.error(
                    "agentTopicName异常! 输入为 => {}",
                    agentTopicName
            );
            return false;
            //throw new MyRuntimeException("agentTopicName异常!" + agentTopicName);
        }

        return true;
    }

    @Override
    public List<ArrayList<String>> SendCommandToAgentBatch(List<String> agentTopicNameList, String executionType, List<String> funcContent, List<String> commandList, List<List<String>> commandListComplete, boolean needResultReplay, boolean durationTask) {

        List<ArrayList<String>> allResult = agentTopicNameList
                .stream()
                .map(
                        agentTopicName -> {
                            return this.SendCommandToAgent(
                                    agentTopicName,
                                    executionType,
                                    funcContent,
                                    null,
                                    commandList,
                                    commandListComplete,
                                    needResultReplay,
                                    durationTask
                            );
                        }
                )
                .collect(Collectors.toList());


        return allResult;
    }


}
