package com.cameleer.server.app.alerting.eval;

import com.cameleer.server.app.search.ClickHouseLogStore;
import com.cameleer.server.core.alerting.AlertRule;
import com.cameleer.server.core.alerting.ConditionKind;
import com.cameleer.server.core.alerting.LogPatternCondition;
import com.cameleer.server.core.runtime.EnvironmentRepository;
import com.cameleer.server.core.search.LogSearchRequest;
import org.springframework.stereotype.Component;

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

@Component
public class LogPatternEvaluator implements ConditionEvaluator<LogPatternCondition> {

    private final ClickHouseLogStore logStore;
    private final EnvironmentRepository envRepo;

    public LogPatternEvaluator(ClickHouseLogStore logStore, EnvironmentRepository envRepo) {
        this.logStore = logStore;
        this.envRepo  = envRepo;
    }

    @Override
    public ConditionKind kind() { return ConditionKind.LOG_PATTERN; }

    @Override
    public EvalResult evaluate(LogPatternCondition c, AlertRule rule, EvalContext ctx) {
        String envSlug = envRepo.findById(rule.environmentId())
                .map(e -> e.slug())
                .orElse(null);

        String appSlug = c.scope() != null ? c.scope().appSlug() : null;

        Instant from = ctx.now().minusSeconds(c.windowSeconds());
        Instant to   = ctx.now();

        // Build a stable cache key so identical queries within the same tick are coalesced.
        String cacheKey = String.join("|",
                envSlug  == null ? "" : envSlug,
                appSlug  == null ? "" : appSlug,
                c.level() == null ? "" : c.level(),
                c.pattern() == null ? "" : c.pattern(),
                from.toString(),
                to.toString()
        );

        long count = ctx.tickCache().getOrCompute(cacheKey, () -> {
            var req = new LogSearchRequest(
                    c.pattern(),
                    c.level() != null ? List.of(c.level()) : List.of(),
                    appSlug,
                    null,   // instanceId
                    null,   // exchangeId
                    null,   // logger
                    envSlug,
                    null,   // sources
                    from,
                    to,
                    null,   // cursor
                    1,      // limit (count query; value irrelevant)
                    "desc", // sort
                    null    // instanceIds
            );
            return logStore.countLogs(req);
        });

        if (count <= c.threshold()) return EvalResult.Clear.INSTANCE;

        return new EvalResult.Firing(
                (double) count,
                (double) c.threshold(),
                Map.of(
                        "app",     Map.of("slug",    appSlug  == null ? "" : appSlug),
                        "pattern", c.pattern() == null ? "" : c.pattern(),
                        "level",   c.level()   == null ? "" : c.level()
                )
        );
    }
}
