package com.microservices.mon.k8s.utils;

import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.mon.k8s.domain.LinkTrackingApplication;
import com.microservices.mon.k8s.domain.SkywalkingMetricType;
import com.microservices.system.api.model.GraphqlQueryVo;

import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * Prometheus查询常量
 */
public class SkywalkingGQLConstant {
    public static GraphqlQueryVo getAllServicesByGroup(String skywalkingGroup) {
        GraphqlQueryVo graphqlQueryVo = new GraphqlQueryVo();
        graphqlQueryVo.setOperationName("getAllServices");
        graphqlQueryVo.setQuery("query getAllServices($group:String!,$duration:Duration!){\n" +
                "  getAllServices(group:$group,duration:$duration ){\n" +
                "    id,\n" +
                "    shortName\n" +
                "  }\n" +
                "}");
        JSONObject variables = new JSONObject();
        variables.put("group", skywalkingGroup);
        variables.put("duration", getTheOneDayDuration());
        graphqlQueryVo.setVariables(variables);
        return graphqlQueryVo;
    }

    public static GraphqlQueryVo searchServicesByKeyword(String keyword) {
        GraphqlQueryVo graphqlQueryVo = new GraphqlQueryVo();
        graphqlQueryVo.setOperationName("searchServices");
        graphqlQueryVo.setQuery("query searchServices($keyword:String!,$duration:Duration!){\n" +
                "  searchServices(keyword:$keyword,duration:$duration ){\n" +
                "    id,\n" +
                "    shortName,\n" +
                "    name,\n" +
                "  }\n" +
                "}");
        JSONObject variables = new JSONObject();
        variables.put("keyword", keyword);
        variables.put("duration", getTheOneDayDuration());
        graphqlQueryVo.setVariables(variables);
        return graphqlQueryVo;
    }

    private static JSONObject getTheOneDayDuration() {
        JSONObject duration = new JSONObject();
        ZonedDateTime endDate = ZonedDateTime.now(ZoneId.of("UTC"));
        ZonedDateTime startDate = endDate.plusDays(-1);
        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        duration.put("start", startDate.format(dateFormat));
        duration.put("end", endDate.format(dateFormat));
        duration.put("step", "HOUR");
        return duration;
    }

    public static GraphqlQueryVo queryMetricDataList(List<LinkTrackingApplication> linkTrackingApplicationList) {
        GraphqlQueryVo graphqlQueryVo = new GraphqlQueryVo();
        graphqlQueryVo.setOperationName("queryMetricDataList");
        JSONObject variables = new JSONObject();
        for (LinkTrackingApplication linkTrackingApplication : linkTrackingApplicationList) {
            variables.put(SkywalkingMetricType.SERVICE_CPM.getFunctionVariable(linkTrackingApplication.getIndex()), genFunctionVariables(SkywalkingMetricType.SERVICE_CPM.getMetricKey(), linkTrackingApplication.getKey()));
            variables.put(SkywalkingMetricType.SERVICE_SLA.getFunctionVariable(linkTrackingApplication.getIndex()), genFunctionVariables(SkywalkingMetricType.SERVICE_SLA.getMetricKey(), linkTrackingApplication.getKey()));
            variables.put(SkywalkingMetricType.SERVICE_RESP_TIME.getFunctionVariable(linkTrackingApplication.getIndex()), genFunctionVariables(SkywalkingMetricType.SERVICE_RESP_TIME.getMetricKey(), linkTrackingApplication.getKey()));
        }
        StringBuffer queryFunctionString = new StringBuffer();
        StringBuffer queryFunctionVariableStringBuffer = new StringBuffer();
        linkTrackingApplicationList.forEach(application -> {
            Integer serviceIndex = application.getIndex();
            for (SkywalkingMetricType metricType : SkywalkingMetricType.values()) {
                String functionName = metricType.getFunctionName(serviceIndex);
                String variable = metricType.getFunctionVariable(serviceIndex);
                queryFunctionVariableStringBuffer.append(String.format("$%s: MetricsCondition!,", variable));
                queryFunctionString.append(String.format("%s: readMetricsValues(condition: $%s, duration: $duration){\n" +
                        "    label\n" +
                        "    values {\n" +
                        "      values {\n" +
                        "       value\n" +
                        "       }\n" +
                        "    }\n" +
                        "  }\n", functionName, variable));
            }
        });
        String queryFunctionVariableString = queryFunctionVariableStringBuffer.toString();
        if (queryFunctionVariableString.endsWith(",")) {
            queryFunctionVariableString = queryFunctionVariableString.replaceFirst(".$", "");
        }


        graphqlQueryVo.setQuery(String.format(
                "query queryMetricDataList($duration:Duration!,%s){\n" +
                        "%s" +
                        "}", queryFunctionVariableString, queryFunctionString
        ));

        JSONObject duration = new JSONObject();
        ZonedDateTime endDate = ZonedDateTime.now(ZoneId.of("UTC"));
        ZonedDateTime startDate = endDate.plusMinutes(-30);
        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
        duration.put("start", startDate.format(dateFormat));
        duration.put("end", endDate.format(dateFormat));
        duration.put("step", "MINUTE");
        variables.put("duration", duration);
        graphqlQueryVo.setVariables(variables);
        return graphqlQueryVo;
    }

    private static JSONObject genFunctionVariables(String functionVariablesType, String serviceKey) {
        JSONObject functionVariables = new JSONObject();
        functionVariables.put("name", functionVariablesType);
        JSONObject functionEntityVariables = new JSONObject();
        functionEntityVariables.put("scope", "Service");
        functionEntityVariables.put("serviceName", serviceKey);
        functionEntityVariables.put("normal", true);
        functionVariables.put("entity", functionEntityVariables);
        return functionVariables;
    }
}
