package com.cameleer.server.app.search;

import com.cameleer.common.model.LogEntry;
import com.cameleer.server.core.ingestion.BufferedLogEntry;
import com.cameleer.server.core.search.LogSearchRequest;
import com.cameleer.server.app.ClickHouseTestHelper;
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.ArrayList;
import java.util.List;
import java.util.Map;

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

@Testcontainers
class ClickHouseLogStoreCountIT {

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

    private JdbcTemplate jdbc;
    private ClickHouseLogStore store;

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

        jdbc = new JdbcTemplate(ds);
        ClickHouseTestHelper.executeInitSql(jdbc);
        jdbc.execute("TRUNCATE TABLE logs");

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

    /** Seed a log row with explicit environment via insertBufferedBatch. */
    private void seed(String tenantId, String environment, String appId, String instanceId,
                      Instant ts, String level, String message) {
        LogEntry entry = new LogEntry(ts, level, "com.example.Foo", message, "main", null, null);
        store.insertBufferedBatch(List.of(
                new BufferedLogEntry(tenantId, environment, instanceId, appId, entry)));
    }

    @Test
    void countLogs_respectsLevelAndPattern() {
        Instant base = Instant.parse("2026-04-19T10:00:00Z");

        // 3 ERROR rows with "TimeoutException" message
        for (int i = 0; i < 3; i++) {
            seed("default", "dev", "orders", "agent-1", base.plusSeconds(i),
                    "ERROR", "TimeoutException occurred");
        }
        // 2 non-matching INFO rows
        for (int i = 0; i < 2; i++) {
            seed("default", "dev", "orders", "agent-1", base.plusSeconds(10 + i),
                    "INFO", "Health check OK");
        }

        long count = store.countLogs(new LogSearchRequest(
                "TimeoutException",
                List.of("ERROR"),
                "orders",
                null,
                null,
                null,
                "dev",
                List.of(),
                base.minusSeconds(10),
                base.plusSeconds(30),
                null,
                100,
                "desc",
                null));

        assertThat(count).isEqualTo(3);
    }

    @Test
    void countLogs_noMatchReturnsZero() {
        Instant base = Instant.parse("2026-04-19T10:00:00Z");
        seed("default", "dev", "orders", "agent-1", base, "INFO", "all good");

        long count = store.countLogs(new LogSearchRequest(
                null,
                List.of("ERROR"),
                "orders",
                null,
                null,
                null,
                "dev",
                List.of(),
                base.minusSeconds(10),
                base.plusSeconds(30),
                null,
                100,
                "desc",
                null));

        assertThat(count).isZero();
    }

    @Test
    void countLogs_environmentFilter_isolatesEnvironments() {
        Instant base = Instant.parse("2026-04-19T10:00:00Z");
        // 2 rows in "dev"
        seed("default", "dev", "orders", "agent-1", base,               "ERROR", "err");
        seed("default", "dev", "orders", "agent-1", base.plusSeconds(1), "ERROR", "err");
        // 1 row in "prod" — should not be counted
        seed("default", "prod", "orders", "agent-2", base.plusSeconds(5), "ERROR", "err");

        long devCount = store.countLogs(new LogSearchRequest(
                null, List.of("ERROR"), "orders", null, null, null,
                "dev", List.of(),
                base.minusSeconds(1), base.plusSeconds(60),
                null, 100, "desc", null));

        assertThat(devCount).isEqualTo(2);
    }
}
