package com.css.simulation.resource.scheduler.infra.configuration.kubernetes;

import api.common.util.OsUtil;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.BatchV1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
public class KubernetesUtil {


    /**
     * 创建 pod
     *
     * @param apiClient     api 客户端
     * @param namespaceName namespace 名称
     * @return pod 名称列表
     */
    @SneakyThrows
    public static V1Pod createPod(ApiClient apiClient, String namespaceName, V1Pod v1Pod) {
        CoreV1Api coreV1Api = new CoreV1Api(apiClient);
        V1Pod result;
        if (namespaceName == null || "".equals(namespaceName) || "default".equals(namespaceName)) {
            result = coreV1Api.createNamespacedPod("default", v1Pod, null, null, null, null);
        } else {
            result = coreV1Api.createNamespacedPod(namespaceName, v1Pod, null, null, null, null);
        }
        return result;
    }

//    /**
//     * 执行 yaml
//     *
//     * @param hostname 主机名
//     * @param username 用户名
//     * @param password 密码
//     * @param yamlPath yaml 文件路径
//     */
//    @SneakyThrows
//    public static void applyYaml(String hostname, String username, String password, String yamlPath) {
//        SshClient client = SshUtil.getClient();
//        ClientSession session = SshUtil.getSession(client, hostname, username, password);
//        SshUtil.execute(session, "kubectl apply -f " + yamlPath);
//        session.close();
//        client.stop();
//    }

    /**
     * 执行 yaml
     *
     * @param yamlPath yaml 文件路径
     */
    @SneakyThrows
    public static void applyYaml(String yamlPath) {
        OsUtil.exec("kubectl apply -f " + yamlPath);
    }

    /**
     * 创建 namespace 命名空间
     *
     * @param apiClient 客户端
     * @param nsName    命名空间名称
     * @return 命名空间对象
     */
    @SneakyThrows
    public static V1Namespace createNs(ApiClient apiClient, String nsName) {
        if (!getNs(apiClient).contains(nsName)) {
            CoreV1Api coreV1Api = new CoreV1Api(apiClient);
            V1Namespace yaml = new V1Namespace();
            //1 apiVersion
            yaml.setApiVersion("v1");
            //2 kind
            yaml.setKind("Namespace");
            //3 metadata
            V1ObjectMeta metadata = new V1ObjectMeta();
            metadata.setName(nsName);
            metadata.setLabels(null);
            yaml.setMetadata(metadata);
            return coreV1Api.createNamespace(yaml, null, null, null, null);
        } else {
            return null;
        }
    }


    /**
     * 获取 namespace 列表
     *
     * @param apiClient api 客户端
     * @return pod 名称列表
     */
    @SneakyThrows
    public static List<String> getNs(ApiClient apiClient) {
        CoreV1Api coreV1Api = new CoreV1Api(apiClient);
        V1NamespaceList v1NamespaceList = coreV1Api.listNamespace(null, null, null, null, null, null, null, null, null, null);
        return v1NamespaceList.getItems().stream().map(ns -> Objects.requireNonNull(ns.getMetadata()).getName()).collect(Collectors.toList());
    }

    public static List<String> getPod(ApiClient apiClient, String namespaceName) {

        try {
            CoreV1Api api = new CoreV1Api(apiClient);
            V1PodList list;
            if (namespaceName == null || "".equals(namespaceName) || "default".equals(namespaceName)) {
                list = api.listNamespacedPod(
                        "default",
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null);
            } else if ("all".equals(namespaceName)) {
                list = api.listPodForAllNamespaces(
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null);
            } else {
                list = api.listNamespacedPod(
                        namespaceName,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null);
            }
            return list.getItems().stream().map(pod -> Objects.requireNonNull(pod.getMetadata()).getName()).collect(Collectors.toList());
        } catch (ApiException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 pod 列表
     *
     * @param apiClient     api 客户端
     * @param namespaceName namespace 名称
     * @return pod 名称列表
     */
    @SneakyThrows
    public static List<String> getPodByPrefix(ApiClient apiClient, String namespaceName, String prefix) {

        CoreV1Api coreV1Api = new CoreV1Api(apiClient);
        V1PodList v1PodList;
        if (namespaceName == null || "".equals(namespaceName) || "default".equals(namespaceName)) {
            v1PodList = coreV1Api.listNamespacedPod(
                    "default",
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);
        } else if ("all".equals(namespaceName)) {
            v1PodList = coreV1Api.listPodForAllNamespaces(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);
        } else {
            v1PodList = coreV1Api.listNamespacedPod(
                    namespaceName,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);
        }
        return v1PodList.getItems().stream()
                .map(pod -> Objects.requireNonNull(pod.getMetadata()).getName())
                .filter(Objects::nonNull)
                .filter(podName -> podName.startsWith(prefix))
                .collect(Collectors.toList());
    }

    /**
     * 删除 pod
     * 异步删除会等待 pod 完全删除完毕，即资源释放完全
     *
     * @param apiClient     api 客户端
     * @param namespaceName namespace 名称
     * @param podName       pod 名称
     */
    public static void deletePod(ApiClient apiClient, String namespaceName, String podName) throws InterruptedException, ApiException {
        deletePodSync(apiClient, namespaceName, podName);
    }

    /**
     * 删除 pod
     * 异步删除会等待 pod 完全删除完毕，即资源释放完全
     *
     * @param apiClient     api 客户端
     * @param namespaceName namespace 名称
     * @param podName       pod 名称
     */
    public static void deletePod2(ApiClient apiClient, String namespaceName, String podName) throws InterruptedException, ApiException {
        deletePodSync(apiClient, namespaceName, podName);
        log.info("等待 pod " + podName + " 的资源释放完成。");
        TimeUnit.SECONDS.sleep(3);
        log.info("pod " + podName + " 资源释放完成。");
    }

    /**
     * 删除 pod
     * 同步删除会等待 pod 完全删除完毕，即资源释放完全
     *
     * @param apiClient     api 客户端
     * @param namespaceName namespace 名称
     * @param podName       pod 名称
     */
    public static void deletePodSync(ApiClient apiClient, String namespaceName, String podName) throws ApiException, InterruptedException {
        log.info("删除命名空间 {} 的 pod：{}", namespaceName, podName);
        CoreV1Api coreV1Api = new CoreV1Api(apiClient);
        coreV1Api.deleteNamespacedPod(podName, namespaceName, null, null, 0, null, null, null);
        // 检查是否删除完毕
        while (true) {
            TimeUnit.SECONDS.sleep(3);
            List<String> podNameList = getPod(apiClient, namespaceName);
            if (!podNameList.contains(podName)) {
                return;
            }
        }
    }

    /**
     * 删除 pod
     * 异步删除不会等待 pod 完全删除完毕，即资源还没有释放
     *
     * @param apiClient     api 客户端
     * @param namespaceName namespace 名称
     * @param podName       pod 名称
     */
    @SneakyThrows
    public static void deletePodAsync(ApiClient apiClient, String namespaceName, String podName) {
        log.info("删除 " + namespaceName + ":" + podName);
        CoreV1Api coreV1Api = new CoreV1Api(apiClient);
        coreV1Api.deleteNamespacedPod(podName, namespaceName, null, null, null, null, null, null);
    }

    public static List<String> getJob(ApiClient apiClient, String namespaceName) throws ApiException {
        BatchV1Api batchV1Api = new BatchV1Api(apiClient);
        V1JobList v1JobList;
        if (namespaceName == null || "".equals(namespaceName) || "default".equals(namespaceName)) {
            v1JobList = batchV1Api.listNamespacedJob(
                    "default",
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);
        } else if ("all".equals(namespaceName)) {
            v1JobList = batchV1Api.listJobForAllNamespaces(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);
        } else {
            v1JobList = batchV1Api.listNamespacedJob(
                    namespaceName,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);
        }
        return v1JobList.getItems().stream().map(pod -> Objects.requireNonNull(pod.getMetadata()).getName()).collect(Collectors.toList());
    }

    public static void deleteJob(ApiClient apiClient, String namespaceName, String jobNameToDelete) throws ApiException {
        List<String> runningJobNameList = getJob(apiClient, namespaceName);
        for (String runningJobName : runningJobNameList) {
            if (jobNameToDelete.equals(runningJobName)) {
                BatchV1Api batchV1Api = new BatchV1Api(apiClient);
                batchV1Api.deleteNamespacedJob(jobNameToDelete, namespaceName, null, null, null, null, null, null);
                break;
            }
        }
    }
}
