package com.multictrl.modules.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.domain.WritePrecision;
import com.influxdb.query.FluxRecord;
import com.influxdb.query.FluxTable;
import com.multictrl.common.config.InfluxConfig;
import com.multictrl.common.utils.DateUtils;
import com.multictrl.common.utils.JsonUtils;
import com.multictrl.modules.business.service.InfluxService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * influxdb操作
 *
 * @author Sdy
 * @since 1.0.0 2026/5/3
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InfluxdbServiceImpl implements InfluxService {
    private final InfluxDBClient influxDBClient;
    private final InfluxConfig influxConfig;
    private static final String FLIGHT_RECORD_QUERY = """
            from(bucket: "flight_records")
              |> range(start: %s, stop: %s)
              |> filter(fn: (r) =>  r["_measurement"] == "%s" %s)
              |> pivot(rowKey:["_time"],columnKey:["_field"],valueColumn:"_value")%s
            """;

    @Override
    public <T> void addRecord(T record) {
        if (influxConfig.getSaveOpen()) {
            influxDBClient.getWriteApiBlocking().writeMeasurement(WritePrecision.MS, record);
        } /*else {
            log.info("数据保存未开启:{}", JsonUtils.toJsonString(record));
        }*/
    }

    @Override
    public <T> List<T> queryData(String startTime, String endTime, String measurement, Map<String, Object> params, Class<T> clazz, String... fields) {
        String condition = String.format(FLIGHT_RECORD_QUERY, DateUtils.toUtc(startTime),
                DateUtils.toUtc(endTime), measurement, assembleCondition(params), checkFields(fields));
        log.info("{}:influx查询语句{}", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN), condition);
        List<FluxTable> dataList = influxDBClient.getQueryApi().query(condition);
        log.info("{}:influx查询结果大小{}", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN), dataList.size());

        return fluxDataToClass(dataList, clazz);
    }

    /**
     * 组装条件
     */
    private String assembleCondition(Map<String, Object> params) {
        String condition = "and r[\"%s\"] == \"%s\"";
        StringBuilder sb = new StringBuilder();
        if (CollectionUtil.isEmpty(params)) {
            return sb.toString();
        }
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String tag = entry.getKey();
            Object value = entry.getValue();
            sb.append(String.format(condition, tag, value)).append(" ");
        }
        return sb.toString();
    }

    /**
     * 数据转换
     */
    public <T> List<T> fluxDataToClass(List<FluxTable> data, Class<T> clazz) {
        List<T> result = new LinkedList<>();
        for (FluxTable ft : data) {
            List<FluxRecord> records = ft.getRecords();
            for (FluxRecord rc : records) {
                try {
                    Map<String, Object> values = rc.getValues();
                    result.add(JsonUtils.parseObjectIgnore(JsonUtils.toJsonString(values), clazz));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
        log.info("{}:influxdb结果转换完成", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        return result;
    }

    /**
     * 检查是否需要返回字段
     */
    public static String checkFields(String... fields) {
        if (fields == null || fields.length == 0) {
            return "";
        } else {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < fields.length; i++) {
                sb.append("\"").append(fields[i]).append("\"");
                if (i < fields.length - 1) {
                    sb.append(", ");
                }
            }
            sb.append("]");
            return "|> keep(columns: " + sb + ")";
        }
    }
}
