package com.cameleer.server.app.storage;

import com.cameleer.server.core.storage.model.MetricsSnapshot;
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 com.zaxxer.hikari.HikariDataSource;

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

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

@Testcontainers
class ClickHouseMetricsStoreIT {

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

    private JdbcTemplate jdbc;
    private ClickHouseMetricsStore 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 agent_metrics (
                tenant_id          LowCardinality(String) DEFAULT 'default',
                collected_at       DateTime64(3),
                instance_id        LowCardinality(String),
                metric_name        LowCardinality(String),
                metric_value       Float64,
                tags               Map(String, String) DEFAULT map(),
                server_received_at DateTime64(3) DEFAULT now64(3)
            )
            ENGINE = MergeTree()
            ORDER BY (tenant_id, instance_id, metric_name, collected_at)
            """);

        jdbc.execute("TRUNCATE TABLE agent_metrics");

        store = new ClickHouseMetricsStore("default", jdbc);
    }

    @Test
    void insertBatch_writesMetricsToClickHouse() {
        List<MetricsSnapshot> batch = List.of(
                new MetricsSnapshot("agent-1", Instant.parse("2026-03-31T10:00:00Z"),
                        "cpu.usage", 75.5, Map.of("host", "server-1")),
                new MetricsSnapshot("agent-1", Instant.parse("2026-03-31T10:00:01Z"),
                        "memory.free", 1024.0, null)
        );

        store.insertBatch(batch);

        Integer count = jdbc.queryForObject(
                "SELECT count() FROM agent_metrics WHERE instance_id = 'agent-1'",
                Integer.class);
        assertThat(count).isEqualTo(2);
    }

    @Test
    void insertBatch_storesTags() {
        store.insertBatch(List.of(
                new MetricsSnapshot("agent-2", Instant.parse("2026-03-31T10:00:00Z"),
                        "disk.used", 500.0, Map.of("mount", "/data", "fs", "ext4"))
        ));

        // Just verify we can read back the row with tags
        Integer count = jdbc.queryForObject(
                "SELECT count() FROM agent_metrics WHERE instance_id = 'agent-2'",
                Integer.class);
        assertThat(count).isEqualTo(1);
    }

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

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

    @Test
    void insertBatch_nullTags_defaultsToEmptyMap() {
        store.insertBatch(List.of(
                new MetricsSnapshot("agent-3", Instant.parse("2026-03-31T10:00:00Z"),
                        "cpu.usage", 50.0, null)
        ));

        Integer count = jdbc.queryForObject(
                "SELECT count() FROM agent_metrics WHERE instance_id = 'agent-3'",
                Integer.class);
        assertThat(count).isEqualTo(1);
    }
}
