package com.lanyuanxiaoyao.service.loki.service;

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.databind.ObjectMapper;
import com.lanyuanxiaoyao.service.configuration.entity.loki.LokiLogLine;
import com.lanyuanxiaoyao.service.loki.configuration.LokiConfiguration;
import com.lanyuanxiaoyao.service.loki.entity.LokiQueryRangeResponse;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.map.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * Loki 查询服务
 *
 * @author lanyuanxiaoyao
 * @date 2023-05-25
 */
@Service
public class LokiQueryService {
    private static final Logger logger = LoggerFactory.getLogger(LokiQueryService.class);

    private final LokiConfiguration lokiConfiguration;
    private final ObjectMapper mapper;

    public LokiQueryService(LokiConfiguration lokiConfiguration, Jackson2ObjectMapperBuilder builder) {
        this.lokiConfiguration = lokiConfiguration;
        this.mapper = builder.build();
    }

    private String buildLokiQuery(ImmutableMap<String, String> queryMap) {
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        String query = queryMap
                .collectValues((key, value) -> StrUtil.format("{}=\"{}\"", key, value))
                .valuesView()
                .makeString(",");
        builder.append(query);
        builder.append("}");
        return builder.toString();
    }

    @Retryable(Throwable.class)
    public ImmutableList<LokiLogLine> queryRange(ImmutableMap<String, String> queryMap, Integer limit) throws Exception {
        String query = URLUtil.encodeQuery(buildLokiQuery(queryMap));
        String queryUrl = StrUtil.format("{}/loki/api/v1/query_range?query={}&limit={}", lokiConfiguration.getHost(), query, limit);
        HttpResponse response = HttpUtil.createGet(queryUrl).execute();
        if (response.isOk()) {
            LokiQueryRangeResponse queryRangeResponse = mapper.readValue(response.body(), LokiQueryRangeResponse.class);
            if (StrUtil.equals("success", queryRangeResponse.getStatus())) {
                ImmutableList<LokiQueryRangeResponse.Result.Line> results = queryRangeResponse.getData().getResult();
                return results.collect(result -> result.getValues().collect(value -> {
                    Long timestamp = Long.valueOf(value.get(0));
                    String data = value.get(1);
                    return new LokiLogLine(result.getStream(), timestamp, data);
                })).flatCollect(list -> list);
            } else {
                throw new Exception("Loki receive not success: " + queryRangeResponse.getStatus());
            }
        } else {
            throw new Exception("Http query error: " + response.getStatus() + " for " + queryUrl);
        }
    }
}
