package com.lanyuanxiaoyao.service.flink.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lanyuanxiaoyao.service.configuration.entity.flink.*;
import com.lanyuanxiaoyao.service.flink.service.FlinkService;
import org.eclipse.collections.api.list.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * @author lanyuanxiaoyao
 * @date 2023-05-04
 */
@Service
public class FlinkServiceImpl implements FlinkService {
    private static final Logger logger = LoggerFactory.getLogger(FlinkServiceImpl.class);

    private final ObjectMapper mapper;

    public FlinkServiceImpl(Jackson2ObjectMapperBuilder builder) {
        mapper = builder.build();
    }

    private String get(String url, String path) {
        String query = URLUtil.normalize(StrUtil.format("{}/{}", url, path));
        logger.debug("Query: {}", query);
        try (HttpResponse response = HttpUtil.createGet(query)
                .setMaxRedirectCount(10)
                .execute()) {
            if (response.isOk()) {
                return response.body();
            } else {
                throw new RuntimeException(StrUtil.format("{} {}", response.getStatus(), response.body()));
            }
        }
    }

    @Cacheable(value = "flink-overview", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkOverview overview(String url) throws JsonProcessingException {
        return mapper.readValue(get(url, "/v1/overview"), FlinkOverview.class);
    }

    @Cacheable(value = "flink-config", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkConfig config(String url) throws JsonProcessingException {
        return mapper.readValue(get(url, "/v1/config"), FlinkConfig.class);
    }

    @Cacheable(value = "flink-jobmanager-config", sync = true)
    @Retryable(Throwable.class)
    @Override
    public ImmutableList<FlinkKeyValue> jobManagerConfig(String url) throws JsonProcessingException {
        return mapper.readValue(get(url, "/v1/jobmanager/config"), new TypeReference<ImmutableList<FlinkKeyValue>>() {
        });
    }

    @Cacheable(value = "flink-vertex-overview", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkVertexOverview vertexOverview(String url) throws JsonProcessingException {
        return mapper.readValue(get(url, "/v1/jobs/overview"), FlinkVertexOverview.class);
    }

    @Cacheable(value = "flink-vertex", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkVertex vertex(String url, String vertexId) throws JsonProcessingException {
        return mapper.readValue(get(url, StrUtil.format("/v1/jobs/{}", vertexId)), FlinkVertex.class);
    }

    @Cacheable(value = "flink-vertex-config", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkVertexConfig vertexConfig(String url, String vertexId) throws JsonProcessingException {
        return mapper.readValue(get(url, StrUtil.format("/v1/jobs/{}/config", vertexId)), FlinkVertexConfig.class);
    }

    @Cacheable(value = "flink-checkpoint-overview", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkCheckpointOverview checkpointOverview(String url, String vertexId) throws JsonProcessingException {
        return mapper.readValue(get(url, StrUtil.format("/v1/jobs/{}/checkpoints", vertexId)), FlinkCheckpointOverview.class);
    }

    @Cacheable(value = "flink-checkpoint", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkCheckpoint checkpoint(String url, String vertexId, Long checkpointId) throws JsonProcessingException {
        return mapper.readValue(get(url, StrUtil.format("/v1/jobs/{}/checkpoints/details/{}", vertexId, checkpointId)), FlinkCheckpoint.class);
    }

    @Cacheable(value = "flink-checkpoint-config", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkCheckpointConfig checkpointConfig(String url, String vertexId) throws JsonProcessingException {
        return mapper.readValue(get(url, StrUtil.format("/v1/jobs/{}/checkpoints/config", vertexId)), FlinkCheckpointConfig.class);
    }

    @Cacheable(value = "flink-taskmanager-overview", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkTaskManagerOverview taskManagerOverview(String url) throws JsonProcessingException {
        return mapper.readValue(get(url, "/v1/taskmanagers"), FlinkTaskManagerOverview.class);
    }

    @Cacheable(value = "flink-taskmanager", sync = true)
    @Retryable(Throwable.class)
    @Override
    public FlinkTaskManager taskManager(String url, String taskManagerId) throws JsonProcessingException {
        return mapper.readValue(get(url, StrUtil.format("/v1/taskmanagers/{}", taskManagerId)), FlinkTaskManager.class);
    }
}
