package com.cameleer.server.app.controller;

import com.cameleer.server.app.dto.AgentMetricsResponse;
import com.cameleer.server.app.dto.MetricBucket;
import com.cameleer.server.app.web.EnvPath;
import com.cameleer.server.core.agent.AgentInfo;
import com.cameleer.server.core.agent.AgentRegistryService;
import com.cameleer.server.core.runtime.Environment;
import com.cameleer.server.core.storage.MetricsQueryStore;
import com.cameleer.server.core.storage.model.MetricTimeSeries;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/v1/environments/{envSlug}/agents/{agentId}/metrics")
public class AgentMetricsController {

    private final MetricsQueryStore metricsQueryStore;
    private final AgentRegistryService registryService;

    public AgentMetricsController(MetricsQueryStore metricsQueryStore,
                                   AgentRegistryService registryService) {
        this.metricsQueryStore = metricsQueryStore;
        this.registryService = registryService;
    }

    @GetMapping
    public ResponseEntity<AgentMetricsResponse> getMetrics(
            @EnvPath Environment env,
            @PathVariable String agentId,
            @RequestParam String names,
            @RequestParam(required = false) Instant from,
            @RequestParam(required = false) Instant to,
            @RequestParam(defaultValue = "60") int buckets,
            @RequestParam(defaultValue = "gauge") String mode) {

        // Defence in depth: if the agent is currently in the registry, reject
        // requests that cross-env (path env doesn't match the agent's env).
        AgentInfo agent = registryService.findById(agentId);
        if (agent != null && !env.slug().equals(agent.environmentId())) {
            return ResponseEntity.notFound().build();
        }

        if (from == null) from = Instant.now().minus(1, ChronoUnit.HOURS);
        if (to == null) to = Instant.now();

        List<String> metricNames = Arrays.asList(names.split(","));

        Map<String, List<MetricTimeSeries.Bucket>> raw = "delta".equalsIgnoreCase(mode)
                ? metricsQueryStore.queryTimeSeriesDelta(agentId, metricNames, from, to, buckets)
                : metricsQueryStore.queryTimeSeries(agentId, metricNames, from, to, buckets);

        Map<String, List<MetricBucket>> result = raw.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        e -> e.getValue().stream()
                                .map(b -> new MetricBucket(b.time(), b.value()))
                                .toList(),
                        (a, b) -> a,
                        LinkedHashMap::new));

        return ResponseEntity.ok(new AgentMetricsResponse(result));
    }
}
