package org.apache.seatunnel.datasource.plugin.influxdb.client;

import org.apache.seatunnel.shade.com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.seatunnel.shade.com.typesafe.config.Config;

import org.apache.seatunnel.datasource.plugin.influxdb.InfluxdbOptionRule;

import org.apache.commons.collections4.CollectionUtils;

import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.InfluxDBClientFactory;
import com.influxdb.query.FluxColumn;
import com.influxdb.query.FluxTable;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
public class InfluxdbsClient implements AutoCloseable {
    private final InfluxDBClient influxDBClient;
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private InfluxdbsClient(InfluxDBClient influxDBClient) {
        this.influxDBClient = influxDBClient;
    }

    @Override
    public void close() throws Exception {
        try {
            influxDBClient.close();
        } catch (Exception e) {
            log.warn("close influxdb connection error", e);
        }
    }

    public List<String> getTables(Config pluginConfig) {
        String org = Optional.of(pluginConfig.getString(InfluxdbOptionRule.ORG.key())).orElse("");
        String sj =
                Optional.of(pluginConfig.getString(InfluxdbOptionRule.HOUR.key())).orElse("-1h");
        String query = "from(bucket: \"primary\") |> range(start: " + sj + ") ";
        List<TableName> tables = influxDBClient.getQueryApi().query(query, org, TableName.class);

        return tables.stream()
                .map(TableName::get_measurement)
                .collect(Collectors.toSet())
                .stream()
                .collect(Collectors.toList());
    }

    public static InfluxdbsClient createInstance(Config pluginConfig) {
        try {
            Optional<String> url = Optional.empty();
            Optional<String> token = Optional.empty();
            Optional<String> bucket = Optional.empty();
            Optional<String> org = Optional.empty();
            if (pluginConfig.hasPath(InfluxdbOptionRule.URL.key())) {
                url = Optional.of(pluginConfig.getString(InfluxdbOptionRule.URL.key()));
            }
            if (pluginConfig.hasPath(InfluxdbOptionRule.TOKEN.key())) {
                token = Optional.of(pluginConfig.getString(InfluxdbOptionRule.TOKEN.key()));
            }

            if (pluginConfig.hasPath(InfluxdbOptionRule.BUCKET.key())) {
                bucket = Optional.of(pluginConfig.getString(InfluxdbOptionRule.BUCKET.key()));
            }

            if (pluginConfig.hasPath(InfluxdbOptionRule.ORG.key())) {
                org = Optional.of(pluginConfig.getString(InfluxdbOptionRule.ORG.key()));
            }
            return createInstance(url, token, bucket, org);
        } catch (Exception e) {
            throw new RuntimeException("Create EsRestClient failed", e);
        }
    }

    public static InfluxdbsClient createInstance(
            Optional<String> url,
            Optional<String> token,
            Optional<String> bucket,
            Optional<String> org) {
        InfluxDBClient influxDBClient1 = getRestClientBuilder(url, token, bucket, org);
        return new InfluxdbsClient(influxDBClient1);
    }

    private static InfluxDBClient getRestClientBuilder(
            Optional<String> url,
            Optional<String> token,
            Optional<String> bucket,
            Optional<String> org) {
        if (url.isPresent() && token.isPresent()) {

            return InfluxDBClientFactory.create(url.get(), token.get().toCharArray());
        } else {
            throw new ResponseException("influxDB  connect  fail  .");
        }
    }

    public Map<String, String> getFieldTypeMapping(Config pluginConfig, String index) {
        String org = Optional.of(pluginConfig.getString(InfluxdbOptionRule.ORG.key())).orElse("");

        String query =
                "from(bucket: \"primary\") |> range(start: "
                        + Optional.of(pluginConfig.getString(InfluxdbOptionRule.HOUR.key()))
                                .orElse("-1h")
                        + ")|> filter(fn: (r) =>  r._measurement == \""
                        + index
                        + "\"   )";
        Map<String, String> mapping = new HashMap<>();
        try {
            List<FluxTable> tables = influxDBClient.getQueryApi().query(query, org);
            if (CollectionUtils.isNotEmpty(tables)) {
                List<List<FluxColumn>> collect =
                        tables.stream().map(m -> m.getColumns()).collect(Collectors.toList());
                // 都是相同的
                List<FluxColumn> fluxColumnList = collect.get(0);
                ;
                fluxColumnList.stream()
                        .forEach(
                                m -> {
                                    mapping.put(m.getLabel(), m.getDataType());
                                });
            }

        } catch (Exception ex) {
            throw new ResponseException(ex);
        }
        return mapping;
    }
}
