package com.njcn.gather.steady.checksquare.component;

import com.njcn.gather.steady.datavie.config.SteadyInfluxDbProperties;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
import com.sun.net.httpserver.HttpServer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据校验 InfluxQL 构造契约测试。
 */
class SteadyChecksquareInfluxQueryComponentTest {

    @Test
    void shouldBuildChecksquareQueryWithoutQualityFlag() {
        SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(new SteadyInfluxDbProperties());
        SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
        field.setMeasurement("data_v");
        field.setField("rms");
        field.setLineId("line-001");
        field.setPhase("A");
        field.setStatType("AVG");

        String query = component.buildChecksquareQuery(field,
                LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                LocalDateTime.of(2026, 5, 1, 23, 59, 59));

        Assertions.assertTrue(query.contains("SELECT \"rms\" AS \"value\""));
        Assertions.assertTrue(query.contains("\"line_id\" = 'line-001'"));
        Assertions.assertTrue(query.contains("\"phasic_type\" = 'A'"));
        Assertions.assertTrue(query.contains("\"value_type\" = 'AVG'"));
        Assertions.assertFalse(query.contains("quality_flag"));
        Assertions.assertFalse(query.contains("GROUP BY time"));
    }

    @Test
    void shouldBuildValuePointQueryWithStatTypeFilter() {
        SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(new SteadyInfluxDbProperties());
        SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
        field.setMeasurement("data_v");
        field.setField("rms");
        field.setLineId("line-001");
        field.setPhase("A");
        field.setStatType("CP95");

        String query = component.buildValuePointQuery(field,
                LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                LocalDateTime.of(2026, 5, 1, 23, 59, 59));

        Assertions.assertTrue(query.contains("SELECT \"rms\" AS \"value\""));
        Assertions.assertTrue(query.contains("\"line_id\" = 'line-001'"));
        Assertions.assertTrue(query.contains("\"phasic_type\" = 'A'"));
        Assertions.assertTrue(query.contains("\"value_type\" = 'CP95'"));
        Assertions.assertTrue(query.endsWith("ORDER BY time ASC"));
    }

    @Test
    void shouldReuseValuePointQueryWithinRequestCache() throws Exception {
        AtomicInteger requestCount = new AtomicInteger();
        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
        server.createContext("/query", exchange -> {
            requestCount.incrementAndGet();
            byte[] body = ("{\"results\":[{\"series\":[{\"values\":["
                    + "[\"2026-05-01T00:00:00Z\",1.23],"
                    + "[\"2026-05-01T00:01:00Z\",2.34]"
                    + "]}]}]}").getBytes(StandardCharsets.UTF_8);
            exchange.sendResponseHeaders(200, body.length);
            exchange.getResponseBody().write(body);
            exchange.close();
        });
        server.start();
        try {
            SteadyInfluxDbProperties properties = new SteadyInfluxDbProperties();
            properties.setUrl("http://127.0.0.1:" + server.getAddress().getPort());
            properties.setDatabase("steady");
            SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(properties);
            SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
            field.setMeasurement("data_v");
            field.setField("rms");
            field.setLineId("line-001");
            field.setPhase("A");
            field.setStatType("AVG");

            component.enableRequestCache();
            component.queryExistingSlots(field,
                    LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                    LocalDateTime.of(2026, 5, 1, 0, 1, 0), 1);
            component.queryValuePoints(field,
                    LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                    LocalDateTime.of(2026, 5, 1, 0, 1, 0), 1);
            component.clearRequestCache();

            Assertions.assertEquals(1, requestCount.get());
        } finally {
            server.stop(0);
        }
    }

    @Test
    void shouldQueryMultipleValueFieldsOnce() throws Exception {
        AtomicInteger requestCount = new AtomicInteger();
        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
        server.createContext("/query", exchange -> {
            requestCount.incrementAndGet();
            byte[] body = ("{\"results\":[{\"series\":[{\"columns\":[\"time\",\"h_2\",\"h_3\"],\"values\":["
                    + "[\"2026-05-01T00:00:00Z\",1.23,2.34],"
                    + "[\"2026-05-01T00:01:00Z\",3.45,null]"
                    + "]}]}]}").getBytes(StandardCharsets.UTF_8);
            exchange.sendResponseHeaders(200, body.length);
            exchange.getResponseBody().write(body);
            exchange.close();
        });
        server.start();
        try {
            SteadyInfluxDbProperties properties = new SteadyInfluxDbProperties();
            properties.setUrl("http://127.0.0.1:" + server.getAddress().getPort());
            properties.setDatabase("steady");
            SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(properties);
            SteadyTrendResolvedFieldBO h2 = buildField("h_2");
            SteadyTrendResolvedFieldBO h3 = buildField("h_3");

            component.enableRequestCache();
            Map<String, java.util.List<com.njcn.gather.steady.checksquare.pojo.bo.SteadyChecksquareValuePointBO>> result =
                    component.queryValuePointMap(Arrays.asList(h2, h3),
                            LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                            LocalDateTime.of(2026, 5, 1, 0, 1, 0), 1);
            component.clearRequestCache();

            Assertions.assertEquals(1, requestCount.get());
            Assertions.assertEquals(2, result.get("h_2").size());
            Assertions.assertEquals(1, result.get("h_3").size());
        } finally {
            server.stop(0);
        }
    }

    @Test
    void shouldQueryMultipleStatTypesOnce() throws Exception {
        AtomicInteger requestCount = new AtomicInteger();
        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
        server.createContext("/query", exchange -> {
            requestCount.incrementAndGet();
            byte[] body = ("{\"results\":[{\"series\":["
                    + "{\"tags\":{\"value_type\":\"MAX\"},\"values\":[[\"2026-05-01T00:00:00Z\",10]]},"
                    + "{\"tags\":{\"value_type\":\"AVG\"},\"values\":[[\"2026-05-01T00:00:00Z\",8]]}"
                    + "]}]}").getBytes(StandardCharsets.UTF_8);
            exchange.sendResponseHeaders(200, body.length);
            exchange.getResponseBody().write(body);
            exchange.close();
        });
        server.start();
        try {
            SteadyInfluxDbProperties properties = new SteadyInfluxDbProperties();
            properties.setUrl("http://127.0.0.1:" + server.getAddress().getPort());
            properties.setDatabase("steady");
            SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(properties);
            SteadyTrendResolvedFieldBO max = buildField("rms");
            max.setMeasurement("data_v");
            max.setStatType("MAX");
            SteadyTrendResolvedFieldBO avg = buildField("rms");
            avg.setMeasurement("data_v");
            avg.setStatType("AVG");

            component.enableRequestCache();
            Map<String, java.util.List<com.njcn.gather.steady.checksquare.pojo.bo.SteadyChecksquareValuePointBO>> result =
                    component.queryStatValuePointMap(Arrays.asList(max, avg),
                            LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                            LocalDateTime.of(2026, 5, 1, 0, 1, 0), 1);
            component.clearRequestCache();

            Assertions.assertEquals(1, requestCount.get());
            Assertions.assertEquals(1, result.get("MAX").size());
            Assertions.assertEquals(1, result.get("AVG").size());
            Assertions.assertEquals(new java.math.BigDecimal("10"), result.get("MAX").get(0).getValue());
            Assertions.assertEquals(new java.math.BigDecimal("8"), result.get("AVG").get(0).getValue());
        } finally {
            server.stop(0);
        }
    }

    @Test
    void shouldBuildStatValuePointQueryWithValueTypeRegex() {
        SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(new SteadyInfluxDbProperties());
        SteadyTrendResolvedFieldBO max = buildField("rms");
        max.setMeasurement("data_v");
        max.setStatType("MAX");
        SteadyTrendResolvedFieldBO avg = buildField("rms");
        avg.setMeasurement("data_v");
        avg.setStatType("AVG");

        String query = component.buildStatValuePointQuery(Arrays.asList(max, avg),
                LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                LocalDateTime.of(2026, 5, 1, 0, 1, 0));

        Assertions.assertTrue(query.contains("SELECT \"rms\" AS \"value\""));
        Assertions.assertTrue(query.contains("\"value_type\" =~ /^(MAX|AVG)$/"));
        Assertions.assertTrue(query.contains("GROUP BY \"value_type\""));
        Assertions.assertTrue(query.endsWith("ORDER BY time ASC"));
    }


    @Test
    void shouldSplitLongValuePointQueryByDay() throws Exception {
        AtomicInteger requestCount = new AtomicInteger();
        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
        server.createContext("/query", exchange -> {
            int index = requestCount.incrementAndGet();
            byte[] body = ("{\"results\":[{\"series\":[{\"values\":["
                    + "[\"2026-05-0" + index + "T00:00:00Z\"," + index + "]"
                    + "]}]}]}").getBytes(StandardCharsets.UTF_8);
            exchange.sendResponseHeaders(200, body.length);
            exchange.getResponseBody().write(body);
            exchange.close();
        });
        server.start();
        try {
            SteadyInfluxDbProperties properties = new SteadyInfluxDbProperties();
            properties.setUrl("http://127.0.0.1:" + server.getAddress().getPort());
            properties.setDatabase("steady");
            SteadyChecksquareInfluxQueryComponent component = new SteadyChecksquareInfluxQueryComponent(properties);

            List<com.njcn.gather.steady.checksquare.pojo.bo.SteadyChecksquareValuePointBO> result =
                    component.queryValuePoints(buildField("h_2"),
                            LocalDateTime.of(2026, 5, 1, 0, 0, 0),
                            LocalDateTime.of(2026, 5, 3, 0, 0, 0), 1);

            Assertions.assertEquals(3, requestCount.get());
            Assertions.assertEquals(3, result.size());
        } finally {
            server.stop(0);
        }
    }

    private SteadyTrendResolvedFieldBO buildField(String fieldName) {
        SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
        field.setMeasurement("data_harmonic");
        field.setField(fieldName);
        field.setLineId("line-001");
        field.setPhase("A");
        field.setStatType("AVG");
        return field;
    }
}
