package com.microservices.mon.k8s.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.context.SecurityContextHolder;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.mon.k8s.domain.*;
import com.microservices.mon.k8s.domain.vo.*;
import com.microservices.mon.k8s.service.IK8sDashboardService;
import com.microservices.mon.k8s.service.IMicroStatusService;
import com.microservices.mon.k8s.utils.PromQLConstant;
import com.microservices.mon.k8s.utils.RancherResponseHandler;
import com.microservices.system.api.RemoteGatewayService;
import com.microservices.system.api.RemoteRancherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@Slf4j
@Service
@RefreshScope
public class MicroStatusServiceImpl extends CommonService implements IMicroStatusService {
    @Autowired
    private RemoteGatewayService remoteGatewayService;
    @Autowired
    private IK8sDashboardService k8sDashboardService;
    @Autowired
    private RemoteRancherService remoteRancherService;

    @Override
    public K8sPodStartStopStatus getPodStartStopStatus() {
        List<K8sNamespace> k8sNamespaceList = k8sDashboardService.getK8sNamespaceList();
        List<String> namespaceNameList = k8sNamespaceList.stream().map(K8sNamespace::getName).collect(Collectors.toList());
        K8sPodStartStopStatus k8sPodStartStopStatus = new K8sPodStartStopStatus();
        JSONObject POD_START_COUNT = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_START_COUNT(cluster_id, namespaceNameList), SecurityContextHolder.getUserKey());
        PrometheusResVo prometheusResVo = POD_START_COUNT.toJavaObject(PrometheusResVo.class);
        k8sPodStartStopStatus.setStartCount(Integer.parseInt(PrometheusResVo.getPromStringValue(prometheusResVo)));

        JSONObject POD_STOP_COUNT = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_COUNT(cluster_id, namespaceNameList), SecurityContextHolder.getUserKey());
        prometheusResVo = POD_STOP_COUNT.toJavaObject(PrometheusResVo.class);
        k8sPodStartStopStatus.setPodCount(Integer.parseInt(PrometheusResVo.getPromStringValue(prometheusResVo)));

        JSONObject POD_START_DATE = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_START_DATE(cluster_id, namespaceNameList), SecurityContextHolder.getUserKey());
        prometheusResVo = POD_START_DATE.toJavaObject(PrometheusResVo.class);
        List<PrometheusResultVo> podStartDateList = PrometheusResVo.getPrometheusResultVoList(prometheusResVo);
        List<K8sPodStartStopDate> podStartStopDateList = new ArrayList<>();
        for (PrometheusResultVo result : podStartDateList) {
            K8sPodStartStopDate podStartStopDate = new K8sPodStartStopDate();
            String podName = result.getMetric().getString("pod");
            podStartStopDate.setPodName(podName);
            Long startTimeStamp = result.getValue().getLong(1);
            podStartStopDate.setStartDate(new Date(startTimeStamp * 1000));
            podStartStopDateList.add(podStartStopDate);
        }

        JSONObject podListJson = RancherResponseHandler.handleJsonObject(remoteRancherService.getK8sPodList(cluster_id, SecurityContextHolder.getUserKey()), "获取所有容器列表");
        if (podListJson != null && podListJson.containsKey("data")) {
            List<RancherPodVo> rancherPodVoList = podListJson.getJSONArray("data").toList(RancherPodVo.class);
            for (RancherPodVo rancherPodVo : rancherPodVoList) {
                if (rancherPodVo.getMetadata() != null && rancherPodVo.getMetadata().getState() != null && rancherPodVo.getStatus() != null) {
                    RancherMetadataState status = rancherPodVo.getMetadata().getState();
                    if (!"running".equalsIgnoreCase(status.getName())) {
                        JSONArray conditionList = rancherPodVo.getStatus().getConditions();
                        for (int i = 0; i < conditionList.size(); i++) {
                            JSONObject condition = conditionList.getJSONObject(i);
                            if (condition != null && condition.containsKey("status") && !condition.getBoolean("status")) {
                                Date stopDate = condition.getDate("lastTransitionTime");
                                podStartStopDateList
                                        .stream()
                                        .filter(x -> x.getPodName().equalsIgnoreCase(rancherPodVo.getMetadata().getName()))
                                        .forEach(x -> {
                                            x.setStopDate(stopDate);
                                            x.setIsRunning(false);
                                        });
                            }
                        }
                    }
                }
            }
        }
        podStartStopDateList.sort(Comparator.comparing(K8sPodStartStopDate::getIsRunning));
        k8sPodStartStopStatus.setPodStartStopDateList(podStartStopDateList);
        return k8sPodStartStopStatus;
    }

    @Override
    public List<K8sPodContainerMetric> getPodCpuUsage(Long step) {
        return getPodContainerMetric(PodMetricType.CPU_USAGE, step);
    }

    @Override
    public List<K8sPodContainerMetric> getPodMemoryUsage(Long step) {
        return getPodContainerMetric(PodMetricType.MEMORY_USAGE, step);
    }

    @Override
    public List<K8sPodContainerMetric> getPodDiskReads(Long step) {
        return getPodContainerMetric(PodMetricType.DISK_READ, step);
    }

    @Override
    public List<K8sPodContainerMetric> getPodDiskWrites(Long step) {
        return getPodContainerMetric(PodMetricType.DISK_WRITE, step);
    }

    @Override
    public List<K8sPodContainerMetric> getPodNetworkReception(Long step) {
        return getPodContainerMetric(PodMetricType.NETWORK_IN, step);
    }

    @Override
    public List<K8sPodContainerMetric> getPodNetworkTransmission(Long step) {
        return getPodContainerMetric(PodMetricType.NETWORK_OUT, step);
    }

    private List<K8sPodContainerMetric> getPodContainerMetric(PodMetricType type, Long step) {
        List<K8sPodContainerMetric> k8sPodContainerMetricList = new ArrayList<>();
        List<K8sNamespace> k8sNamespaceList = k8sDashboardService.getK8sNamespaceList();
        List<String> namespaceNameList = k8sNamespaceList.stream().map(K8sNamespace::getName).collect(Collectors.toList());
        // 设置默认统计频率
        if (step == null || step <= 0) {
            step = 10L;
        }
        // 设置查询时间范围为最近一小时
        Date now = DateUtils.getNowDate();
        final long endTime = now.getTime() / 1000;
        // 开始时间为当前时间减去1小时
        long startTime = now.getTime() / 1000 - 30 * 60;
        String query = null;
        switch (type) {
            case CPU_USAGE:
                query = PromQLConstant.ALL_POD_CPU_USAGE(namespaceNameList);
                break;
            case MEMORY_USAGE:
                query = PromQLConstant.ALL_POD_MEMORY_USAGE(namespaceNameList);
                break;
            case NETWORK_IN:
                query = PromQLConstant.ALL_POD_NETWORK_RECEPTION(namespaceNameList);
                break;
            case NETWORK_OUT:
                query = PromQLConstant.ALL_POD_NETWORK_TRANSMISSION(namespaceNameList);
                break;
            case DISK_READ:
                query = PromQLConstant.ALL_POD_DISK_READS(namespaceNameList);
                break;
            case DISK_WRITE:
                query = PromQLConstant.ALL_POD_DISK_WRITES(namespaceNameList);
                break;
        }
        JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(query, step, startTime, endTime, SecurityContextHolder.getUserKey());
        if (metricResJson != null && metricResJson.containsKey("data")) {
            PrometheusResVo prometheusResVo = metricResJson.toJavaObject(PrometheusResVo.class);
            if (prometheusResVo != null && prometheusResVo.isSuccess()) {
                List<PrometheusResultVo> prometheusResultVoList = prometheusResVo.getData().getResult();
                for (PrometheusResultVo prometheusResultVo : prometheusResultVoList) {
                    K8sPodContainerMetric k8sPodContainerMetric = new K8sPodContainerMetric();
                    k8sPodContainerMetric.setPodName(prometheusResultVo.getMetric().getString("container_label_io_kubernetes_pod_name"));
                    k8sPodContainerMetric.setData(MetricCommonData.prometheusResultVoToMetric(prometheusResultVo.getValues()));
                    k8sPodContainerMetricList.add(k8sPodContainerMetric);
                }
            }
        }
        return k8sPodContainerMetricList;
    }

    enum PodMetricType {
        CPU_USAGE,
        MEMORY_USAGE,
        NETWORK_IN,
        NETWORK_OUT,
        DISK_READ,
        DISK_WRITE,
    }
}
