package com.cameleer.server.app.storage;

import com.cameleer.server.core.analytics.UsageEvent;
import com.cameleer.server.core.analytics.UsageStats;
import com.cameleer.server.core.analytics.UsageTracker;
import com.cameleer.server.core.ingestion.WriteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

public class ClickHouseUsageTracker implements UsageTracker {

    private static final Logger log = LoggerFactory.getLogger(ClickHouseUsageTracker.class);

    private final String tenantId;
    private final JdbcTemplate jdbc;
    private final WriteBuffer<UsageEvent> buffer;

    public ClickHouseUsageTracker(String tenantId, JdbcTemplate jdbc, WriteBuffer<UsageEvent> buffer) {
        this.tenantId = tenantId;
        this.jdbc = jdbc;
        this.buffer = buffer;
    }

    @Override
    public void track(UsageEvent event) {
        buffer.offerOrWarn(event);
    }

    public void flush() {
        List<UsageEvent> batch = buffer.drain(200);
        if (batch.isEmpty()) return;

        jdbc.batchUpdate("""
                INSERT INTO usage_events (tenant_id, timestamp, username, method, path, normalized,
                    status_code, duration_ms, query_params)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                batch.stream().map(e -> new Object[]{
                        tenantId,
                        Timestamp.from(e.timestamp()),
                        e.username(),
                        e.method(),
                        e.path(),
                        e.normalized(),
                        e.statusCode(),
                        e.durationMs(),
                        e.queryParams() != null ? e.queryParams() : ""
                }).toList());

        log.debug("Flushed {} usage events to ClickHouse", batch.size());
    }

    public List<UsageStats> queryByEndpoint(Instant from, Instant to, String username) {
        StringBuilder sql = new StringBuilder("""
                SELECT concat(method, ' ', normalized) AS key,
                       count() AS cnt,
                       avg(duration_ms) AS avg_dur
                FROM usage_events
                WHERE tenant_id = ? AND timestamp >= ? AND timestamp < ?
                """);
        List<Object> params = new ArrayList<>();
        params.add(tenantId);
        params.add(Timestamp.from(from));
        params.add(Timestamp.from(to));

        if (username != null && !username.isBlank()) {
            sql.append(" AND username = ?");
            params.add(username);
        }
        sql.append(" GROUP BY key ORDER BY cnt DESC LIMIT 100");

        return jdbc.query(sql.toString(), (rs, i) -> new UsageStats(
                rs.getString("key"), rs.getLong("cnt"), rs.getLong("avg_dur")),
                params.toArray());
    }

    public List<UsageStats> queryByUser(Instant from, Instant to) {
        String sql = """
                SELECT username AS key, count() AS cnt, avg(duration_ms) AS avg_dur
                FROM usage_events
                WHERE tenant_id = ? AND timestamp >= ? AND timestamp < ?
                GROUP BY key ORDER BY cnt DESC LIMIT 100
                """;

        return jdbc.query(sql, (rs, i) -> new UsageStats(
                rs.getString("key"), rs.getLong("cnt"), rs.getLong("avg_dur")),
                tenantId, Timestamp.from(from), Timestamp.from(to));
    }

    public List<UsageStats> queryByHour(Instant from, Instant to, String username) {
        StringBuilder sql = new StringBuilder("""
                SELECT formatDateTime(toStartOfHour(timestamp), '%%Y-%%m-%%d %%H:00') AS key,
                       count() AS cnt,
                       avg(duration_ms) AS avg_dur
                FROM usage_events
                WHERE tenant_id = ? AND timestamp >= ? AND timestamp < ?
                """);
        List<Object> params = new ArrayList<>();
        params.add(tenantId);
        params.add(Timestamp.from(from));
        params.add(Timestamp.from(to));

        if (username != null && !username.isBlank()) {
            sql.append(" AND username = ?");
            params.add(username);
        }
        sql.append(" GROUP BY key ORDER BY key LIMIT 720");

        return jdbc.query(sql.toString(), (rs, i) -> new UsageStats(
                rs.getString("key"), rs.getLong("cnt"), rs.getLong("avg_dur")),
                params.toArray());
    }
}
