package com.cameleer.server.app.storage;

import com.cameleer.server.core.storage.model.ServerMetricSample;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.clickhouse.ClickHouseContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.time.Instant;
import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

@Testcontainers
class ClickHouseServerMetricsStoreIT {

    @Container
    static final ClickHouseContainer clickhouse =
            new ClickHouseContainer("clickhouse/clickhouse-server:24.12");

    private JdbcTemplate jdbc;
    private ClickHouseServerMetricsStore store;

    @BeforeEach
    void setUp() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(clickhouse.getJdbcUrl());
        ds.setUsername(clickhouse.getUsername());
        ds.setPassword(clickhouse.getPassword());

        jdbc = new JdbcTemplate(ds);

        jdbc.execute("""
            CREATE TABLE IF NOT EXISTS server_metrics (
                tenant_id          LowCardinality(String) DEFAULT 'default',
                collected_at       DateTime64(3),
                server_instance_id LowCardinality(String),
                metric_name        LowCardinality(String),
                metric_type        LowCardinality(String),
                statistic          LowCardinality(String) DEFAULT 'value',
                metric_value       Float64,
                tags               Map(String, String) DEFAULT map(),
                server_received_at DateTime64(3) DEFAULT now64(3)
            )
            ENGINE = MergeTree()
            ORDER BY (tenant_id, collected_at, server_instance_id, metric_name, statistic)
            """);

        jdbc.execute("TRUNCATE TABLE server_metrics");

        store = new ClickHouseServerMetricsStore(jdbc);
    }

    @Test
    void insertBatch_roundTripsAllColumns() {
        Instant ts = Instant.parse("2026-04-23T12:00:00Z");
        store.insertBatch(List.of(
                new ServerMetricSample("tenant-a", ts, "srv-1",
                        "cameleer.ingestion.drops", "counter", "count", 17.0,
                        Map.of("reason", "buffer_full")),
                new ServerMetricSample("tenant-a", ts, "srv-1",
                        "jvm.memory.used", "gauge", "value", 1_048_576.0,
                        Map.of("area", "heap", "id", "G1 Eden Space"))
        ));

        Integer count = jdbc.queryForObject(
                "SELECT count() FROM server_metrics WHERE tenant_id = 'tenant-a'",
                Integer.class);
        assertThat(count).isEqualTo(2);

        Double dropsValue = jdbc.queryForObject(
                """
                SELECT metric_value FROM server_metrics
                WHERE tenant_id = 'tenant-a'
                  AND server_instance_id = 'srv-1'
                  AND metric_name = 'cameleer.ingestion.drops'
                  AND statistic = 'count'
                """,
                Double.class);
        assertThat(dropsValue).isEqualTo(17.0);

        String heapArea = jdbc.queryForObject(
                """
                SELECT tags['area'] FROM server_metrics
                WHERE tenant_id = 'tenant-a'
                  AND metric_name = 'jvm.memory.used'
                """,
                String.class);
        assertThat(heapArea).isEqualTo("heap");
    }

    @Test
    void insertBatch_emptyList_doesNothing() {
        store.insertBatch(List.of());

        Integer count = jdbc.queryForObject(
                "SELECT count() FROM server_metrics", Integer.class);
        assertThat(count).isEqualTo(0);
    }

    @Test
    void insertBatch_nullTags_storesEmptyMap() {
        store.insertBatch(List.of(
                new ServerMetricSample("default", Instant.parse("2026-04-23T12:00:00Z"),
                        "srv-2", "process.cpu.usage", "gauge", "value", 0.12, null)
        ));

        Integer count = jdbc.queryForObject(
                "SELECT count() FROM server_metrics WHERE server_instance_id = 'srv-2'",
                Integer.class);
        assertThat(count).isEqualTo(1);
    }
}
