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

import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.context.SecurityContextHolder;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.StringUtils;
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.IMonCommonAsyncService;
import com.microservices.mon.k8s.utils.CustomExecutorFactory;
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 MonCommonAsyncServiceImpl extends CommonService implements IMonCommonAsyncService {
    @Autowired
    private RemoteGatewayService remoteGatewayService;
    @Autowired
    @Lazy
    private IK8sDashboardService k8sDashboardService;
    @Autowired
    private RemoteRancherService remoteRancherService;

    @Override
    public K8sClusterStatus getClusterStatus(String query) {
        K8sClusterStatus k8sClusterStatus = new K8sClusterStatus();
        CountDownLatch countDownLatch = new CountDownLatch(9);
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject nodeCountJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_NODE_COUNT(cluster_id), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setNodeCount(nodeCountJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }

        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject unavailableNodeCountJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_UNAVAILABLE_NODE_COUNT(cluster_id), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setUnavailableNodeCount(unavailableNodeCountJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject cpuUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_CPU_USAGE(cluster_id), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setCpuUsage(cpuUsageJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject podUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_POD_USAGE(cluster_id), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setPodUsage(podUsageJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject memoryUsageJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.CLUSTER_MEMORY_USAGE(cluster_id), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setMemoryUsage(memoryUsageJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject totalRequestCountTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.TOTAL_REQUEST_COUNT_TODAY, SecurityContextHolder.getUserKey());
                k8sClusterStatus.setTotalRequestCountToday(totalRequestCountTodayJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject averageRequestProcessingTimeTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.AVERAGE_REQUEST_PROCESSING_TIME_TODAY, SecurityContextHolder.getUserKey());
                k8sClusterStatus.setAverageRequestProcessingTimeToday(averageRequestProcessingTimeTodayJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                JSONObject requestSuccessRateTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.REQUEST_SUCCESS_RATE_TODAY, SecurityContextHolder.getUserKey());
                k8sClusterStatus.setRequestSuccessRateToday(requestSuccessRateTodayJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                List<K8sNamespace> k8sNamespaceList = k8sDashboardService.getNamespaceDetailList(false, null);
                k8sClusterStatus.setMicroserviceApplicationCount(k8sNamespaceList);
                List<String> namespaceNameList = k8sNamespaceList.stream().map(K8sNamespace::getName).collect(Collectors.toList());
                JSONObject microserviceRestartCountTodayJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.MICROSERVICE_RESTART_COUNT_TODAY(cluster_id, namespaceNameList), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setMicroserviceRestartCountToday(microserviceRestartCountTodayJson.toJavaObject(PrometheusResVo.class));

                JSONObject podStatusJson = remoteGatewayService.getPrometheusQueryRes(PromQLConstant.POD_STATUS(cluster_id, namespaceNameList), SecurityContextHolder.getUserKey());
                k8sClusterStatus.setPodStatus(podStatusJson.toJavaObject(PrometheusResVo.class));
            } finally {
                countDownLatch.countDown();
            }
        });
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            log.error("集群状态获取失败:{0}", e);
            throw new ServiceException("集群状态获取失败");
        }
        return k8sClusterStatus;
    }

    @Override
    public List<K8sNamespace> getNamespaceDetailList(boolean needPod, String search) {
        List<RancherApplicationVo> rancherApplicationVoList = new ArrayList<>();
        List<K8sNamespace> k8sNamespaceList = new ArrayList<>();
        CountDownLatch applicationCountDownLatch = new CountDownLatch(4);
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                //调用rancher远程接口获取所有daemonsets列表
                JSONObject daemonsetsJsonObject = RancherResponseHandler.handleJsonObject(remoteRancherService.getK8sDaemonsetsList(cluster_id, SecurityContextHolder.getUserKey()), "获取DaemonSet类型应用");
                if (daemonsetsJsonObject != null && daemonsetsJsonObject.containsKey("data")) {
                    rancherApplicationVoList.addAll(daemonsetsJsonObject.getJSONArray("data").toList(RancherApplicationVo.class));
                }
            } finally {
                applicationCountDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                //调用rancher远程接口获取所有deploy列表
                JSONObject deployJsonObject = RancherResponseHandler.handleJsonObject(remoteRancherService.getK8sDeployList(cluster_id, SecurityContextHolder.getUserKey()), "获取Deploy类型应用");
                if (deployJsonObject != null && deployJsonObject.containsKey("data")) {
                    rancherApplicationVoList.addAll(deployJsonObject.getJSONArray("data").toList(RancherApplicationVo.class));
                }
            } finally {
                applicationCountDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                //调用rancher远程接口获取所有Stateful列表
                JSONObject statefulJsonObject = RancherResponseHandler.handleJsonObject(remoteRancherService
                        .getK8sStatefulList(cluster_id, SecurityContextHolder.getUserKey()), "获取StatefulSet类型应用");
                if (statefulJsonObject != null && statefulJsonObject.containsKey("data")) {
                    rancherApplicationVoList.addAll(statefulJsonObject.getJSONArray("data").toList(RancherApplicationVo.class));
                }
            } finally {
                applicationCountDownLatch.countDown();
            }
        });
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                k8sNamespaceList.addAll(k8sDashboardService.getK8sNamespaceList());
            } finally {
                applicationCountDownLatch.countDown();
            }
        });
        try {
            applicationCountDownLatch.await();
        } catch (InterruptedException e) {
            log.error("集群应用列表获取失败:{0}", e);
            throw new ServiceException("集群应用列表获取失败");
        }


        // 将rancher对象转换为k8s对象
        List<K8sApplication> k8sApplicationList = rancherApplicationVoList
                .stream()
                .map(RancherApplicationVo::toK8sApplication)
                .filter(x -> StringUtils.isEmpty(search) || x.getName().contains(search) || (StringUtils.isNotEmpty(x.getAlias()) && x.getAlias().contains(search)))
                .collect(Collectors.toList());

        CountDownLatch podCountDownLatch = new CountDownLatch(k8sNamespaceList.size());
        for (int i = 0; i < k8sNamespaceList.size(); i++) {
            int finalI = i;
            CustomExecutorFactory.threadPoolExecutor.execute(() -> {
                try {
                    K8sNamespace k8sNamespace = k8sNamespaceList.get(finalI);
                    List<K8sApplication> namespaceApplicationList = k8sApplicationList
                            .stream()
                            .filter(k8sApplication -> k8sApplication.getNamespace().equals(k8sNamespace.getName()))
                            .collect(Collectors.toList());
                    if (needPod) {
                        // 获取命名空间下pod列表
                        JSONObject podListJson = RancherResponseHandler.handleJsonObject(remoteRancherService.getK8sPodListByNamespace(cluster_id, k8sNamespace.getName(), SecurityContextHolder.getUserKey()), "获取容器列表");
                        List<RancherPodVo> rancherPodVoList;
                        if (podListJson != null && podListJson.containsKey("data")) {
                            rancherPodVoList = podListJson.getJSONArray("data").toList(RancherPodVo.class);
                            for (int j = 0; j < namespaceApplicationList.size(); j++) {
                                K8sApplication k8sApplication = namespaceApplicationList.get(j);
                                List<RancherPodVo> applicationToPodList = rancherPodVoList.stream()
                                        .filter(rancherPodVo -> {
                                            if (!StringUtils.isEmpty(k8sApplication.getPodSelector())) {
                                                String[] podSelector = k8sApplication.getPodSelector().split("=");
                                                return rancherPodVo.getMetadata().getLabels().containsKey(podSelector[0])
                                                        && rancherPodVo.getMetadata().getLabels().get(podSelector[0]).equals(podSelector[1]);
                                            }
                                            return false;
                                        })
                                        .collect(Collectors.toList());
                                List<K8sApplicationPod> podList = applicationToPodList.stream().map(RancherPodVo::toK8sApplicationPod).sorted(Comparator.comparing(K8sApplicationPod::getName)).collect(Collectors.toList());
                                k8sApplication.setPodList(podList);
                                k8sApplication.setRestartCount(podList.stream().filter(x -> x.getRestartCount() != null).mapToInt(K8sApplicationPod::getRestartCount).sum());
                                namespaceApplicationList.set(j, k8sApplication);
                            }
                        }
                    }
                    namespaceApplicationList.sort(Comparator.comparing(K8sApplication::getName));
                    k8sNamespace.setApplicationList(namespaceApplicationList);
                    k8sNamespaceList.set(finalI, k8sNamespace);
                } finally {
                    podCountDownLatch.countDown();
                }
            });
        }
        try {
            podCountDownLatch.await();
        } catch (InterruptedException e) {
            log.error("K8S应用对象数据转换失败:{0}", e);
            throw new ServiceException("K8S应用对象数据转换失败");
        }
        k8sNamespaceList.sort(Comparator.comparing(K8sNamespace::getName));
        return k8sNamespaceList.stream().filter(x -> !x.getApplicationList().isEmpty()).collect(Collectors.toList());
    }

    @Override
    public List<K8sApplicationPod> getPodList() {
        List<K8sNamespace> k8sNamespaceList = k8sDashboardService.getK8sNamespaceList();
        CountDownLatch podCountDownLatch = new CountDownLatch(k8sNamespaceList.size());
        List<K8sApplicationPod> podList = new ArrayList<>();
        for (int i = 0; i < k8sNamespaceList.size(); i++) {
            int finalI = i;
            CustomExecutorFactory.threadPoolExecutor.execute(() -> {
                try {
                    K8sNamespace k8sNamespace = k8sNamespaceList.get(finalI);
                    // 获取命名空间下pod列表
                    JSONObject podListJson = RancherResponseHandler.handleJsonObject(remoteRancherService.getK8sPodListByNamespace(cluster_id, k8sNamespace.getName(), SecurityContextHolder.getUserKey()), "获取容器列表");

                    if (podListJson != null && podListJson.containsKey("data")) {
                        List<RancherPodVo> rancherPodVoList = podListJson.getJSONArray("data").toList(RancherPodVo.class);
                        podList.addAll(rancherPodVoList.stream().map(RancherPodVo::toK8sApplicationPod).collect(Collectors.toList()));
                    }
                } finally {
                    podCountDownLatch.countDown();
                }

            });
        }
        try {
            podCountDownLatch.await();
        } catch (InterruptedException e) {
            log.error("获取可视化面板容器列表失败:{0}", e);
            throw new ServiceException("获取可视化面板容器列表失败");
        }
        podList.sort(Comparator.comparing(K8sApplicationPod::getName));
        podList.sort(Comparator.comparing(K8sApplicationPod::getNamespace));
        return podList;

    }

    @Override
    public K8sPodContainerMetricOverview getPodStatus(String podName, Long step) {
        K8sPodContainerMetricOverview k8SPodContainerMetricOverview = new K8sPodContainerMetricOverview();
        // 设置默认统计频率
        if (step == null || step <= 0) {
            step = 10L;
        }
        CountDownLatch countDownLatch = new CountDownLatch(6);
        // 设置查询时间范围为最近一小时
        Date now = DateUtils.getNowDate();
        final long endTime = now.getTime() / 1000;
        // 开始时间为当前时间减去1小时
        long startTime = now.getTime() / 1000 - 60 * 60;


        k8SPodContainerMetricOverview.setPodName(podName);

        Long finalStep = step;
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                // 获取CPU使用率
                JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.POD_CPU_USAGE(podName), finalStep, startTime, endTime, SecurityContextHolder.getUserKey());
                List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                k8SPodContainerMetricOverview.setCpuUsage(metricCommonDataList);
            } finally {
                countDownLatch.countDown();
            }
        });

        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                // 获取内存使用情况
                JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.POD_MEMORY_USAGE(podName), finalStep, startTime, endTime, SecurityContextHolder.getUserKey());
                List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                k8SPodContainerMetricOverview.setMemoryUsage(metricCommonDataList);
            } finally {
                countDownLatch.countDown();
            }
        });

        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                // 获取磁盘写入情况
                JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.POD_DISK_WRITES(podName), finalStep, startTime, endTime, SecurityContextHolder.getUserKey());
                List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                k8SPodContainerMetricOverview.setDiskWrites(metricCommonDataList);
            } finally {
                countDownLatch.countDown();
            }
        });

        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                // 获取磁盘读取情况
                JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.POD_DISK_READS(podName), finalStep, startTime, endTime, SecurityContextHolder.getUserKey());
                List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                k8SPodContainerMetricOverview.setDiskReads(metricCommonDataList);
            } finally {
                countDownLatch.countDown();
            }
        });

        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                // 获取网络发送情况
                JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.POD_NETWORK_TRANSMISSION(podName), finalStep, startTime, endTime, SecurityContextHolder.getUserKey());
                List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                k8SPodContainerMetricOverview.setNetworkTransmission(metricCommonDataList);
            } finally {
                countDownLatch.countDown();
            }
        });

        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            try {
                // 获取网络接收情况
                JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.POD_NETWORK_RECEPTION(podName), finalStep, startTime, endTime, SecurityContextHolder.getUserKey());
                List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                k8SPodContainerMetricOverview.setNetworkReception(metricCommonDataList);
            } finally {
                countDownLatch.countDown();
            }
        });

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            log.error("获取微服务运行状态监控数据失败:{0}", e);
            throw new ServiceException("获取微服务运行状态监控数据失败");
        }
        return k8SPodContainerMetricOverview;
    }

    @Override
    public List<K8SResourceUsage> getResourceUsageList(List<JSONObject> metricList, Date[] startAndEndDates, Long step) {
        List<K8SResourceUsage> resourceUsageList =  Collections.synchronizedList(new ArrayList<>());
        CountDownLatch countDownLatch = new CountDownLatch(metricList.size() * 2);
        for (JSONObject metric : metricList) {
            String nodeInstance = metric.getString("instance");
            String nodeIp = metric.getString("ip");
            CustomExecutorFactory.threadPoolExecutor.execute(() -> {
                try {
                    JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.NODE_CPU_USAGE(nodeIp), step, startAndEndDates[0].getTime() / 1000, startAndEndDates[1].getTime() / 1000, SecurityContextHolder.getUserKey());
                    List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                    for (MetricCommonData metricCommonData : metricCommonDataList) {
                        K8SResourceUsage k8SResourceUsage = new K8SResourceUsage();
                        k8SResourceUsage.setOccurredTime(metricCommonData.getDate());
                        k8SResourceUsage.setResourceType("K8S节点服务器");
                        k8SResourceUsage.setResourceObject(String.format("%s(%s)", nodeInstance, nodeIp));
                        k8SResourceUsage.setMessage(String.format("CPU使用率为：%s%%", metricCommonData.getValue()));
                        resourceUsageList.add(k8SResourceUsage);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
            CustomExecutorFactory.threadPoolExecutor.execute(() -> {
                try {
                    JSONObject metricResJson = remoteGatewayService.getPrometheusQueryRangeRes(PromQLConstant.NODE_MEMORY_USAGE(nodeIp), step, startAndEndDates[0].getTime() / 1000, startAndEndDates[1].getTime() / 1000, SecurityContextHolder.getUserKey());
                    List<MetricCommonData> metricCommonDataList = k8sDashboardService.getMetricCommonDataList(metricResJson);
                    for (MetricCommonData metricCommonData : metricCommonDataList) {
                        K8SResourceUsage k8SResourceUsage = new K8SResourceUsage();
                        k8SResourceUsage.setOccurredTime(metricCommonData.getDate());
                        k8SResourceUsage.setResourceType("K8S节点服务器");
                        k8SResourceUsage.setResourceObject(String.format("%s(%s)", nodeInstance, nodeIp));
                        k8SResourceUsage.setMessage(String.format("内存使用率为：%s%%", metricCommonData.getValue()));
                        resourceUsageList.add(k8SResourceUsage);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
        }


        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            log.error("获取K8S资源占用数据失败:{0}", e);
            throw new ServiceException("获取K8S资源占用数据失败");
        }
        return resourceUsageList;
    }
}
