package com.bsmlab.dfx.agent.task.status;

import com.bsmlab.dfx.agent.config.AgentConfigDto;
import com.bsmlab.dfx.agent.config.AgentConfigReader;
import com.bsmlab.dfx.agent.listener.dto.AckDto;
import com.bsmlab.dfx.agent.support.MessageUtils;
import com.bsmlab.dfx.agent.task.dropbox.DropBoxService;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;

import java.util.List;
import java.util.concurrent.ScheduledFuture;

@Service
@Slf4j
@RequiredArgsConstructor
public class StatusCheckerSchedulerService {
    private final ThreadPoolTaskScheduler statusCheckerThreadPoolTaskScheduler;
    private final AgentConfigReader agentConfigReader;
    private final DropBoxService dropBoxService;
    private ScheduledFuture<?> scheduledFuture;

    // StartupRunner 로 부터 실행됨
    public void launch() {
        log.debug("StatusCheckerSchedulerService launch");
        String cron = agentConfigReader.getAgentConfigDto().getStatusChecker().getCron();
        this.scheduledFuture = statusCheckerThreadPoolTaskScheduler.schedule(() -> run(),  new CronTrigger(cron));
    }

    // statusCheckerThreadPoolTaskScheduler 가 실행함
    public void run() {
        log.info("status-check extra poll size: {}", dropBoxService.getPollSize());
        List<AgentConfigDto.KnownAgent> knownAgentList = this.agentConfigReader.getAgentConfigDto().getKnownAgentList();
        if(knownAgentList != null) {
            for(AgentConfigDto.KnownAgent knownAgent : knownAgentList) {
                AckDto ackDto = null;
                try {
                    ackDto = MessageUtils.alive(this.agentConfigReader, knownAgent);
                    log.debug("StatusChecker received ack from {} ack: {}", knownAgent.getHostName(), ackDto);
                    if(AckDto.ResultType.PROCESS_SUCCESS == ackDto.getResult()) {
                        // known agent is alive
                        this.agentConfigReader.setKnownAgentStatus(knownAgent.getHostId(), "ALIVE");
                        log.debug("known agent {} {} is ALIVE", knownAgent.getHostId(), knownAgent.getHostName());
                    }
                    else {
                        // known agent is down
                        this.agentConfigReader.setKnownAgentStatus(knownAgent.getHostId(), "DOWN");
                        log.debug("known agent {} {} is DOWN", knownAgent.getHostId(), knownAgent.getHostName());
                    }
                }
                catch (JsonProcessingException e) {
                    this.agentConfigReader.setKnownAgentStatus(knownAgent.getHostId(), "DOWN");
                    log.debug("known agent {} {} alive message is not valid then set DOWN", knownAgent.getHostId(), knownAgent.getHostName());
                }
                catch (ResourceAccessException e) {
                    this.agentConfigReader.setKnownAgentStatus(knownAgent.getHostId(), "DOWN");
                    log.debug("known agent {} {} connection timeout", knownAgent.getHostId(), knownAgent.getHostName());
                }
            }
        }
        if(StringUtils.isNotEmpty(this.agentConfigReader.getAgentConfigDto().getStatusChecker().getConsoleHostName()) && this.agentConfigReader.getAgentConfigDto().getStatusChecker().getConsoleListenPort() > 0) {
            AckDto ackDto = null;
            try {
                ackDto = MessageUtils.announceInformation(this.agentConfigReader);
                log.debug("StatusChecker received ack from {} ack: {}", this.agentConfigReader.getAgentConfigDto().getStatusChecker().getConsoleHostName(), ackDto);
                if(AckDto.ResultType.PROCESS_SUCCESS == ackDto.getResult()) {
                    // console response
                    log.debug("console {} is ALIVE", this.agentConfigReader.getAgentConfigDto().getStatusChecker().getConsoleHostName());
                    this.agentConfigReader.setConnectedConsole(true);
                }
                else {
                    // console is down
                    log.debug("console {} is DOWN", this.agentConfigReader.getAgentConfigDto().getStatusChecker().getConsoleHostName());
                    this.agentConfigReader.setConnectedConsole(false);
                }
            } catch (JsonProcessingException e) {
                log.debug("Console {} information message is not valid then set DOWN", this.agentConfigReader.getAgentConfigDto().getStatusChecker().getConsoleHostName());
            }
        }
    }
}
