package com.cameleer.server.app.controller;

import com.cameleer.common.model.RouteExecution;
import com.cameleer.server.core.agent.AgentInfo;
import com.cameleer.server.core.agent.AgentRegistryService;
import com.cameleer.server.core.ingestion.ChunkAccumulator;
import com.cameleer.server.core.ingestion.IngestionService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * Legacy ingestion endpoint for route execution data (PostgreSQL path).
 * <p>
 * Accepts both single {@link RouteExecution} and arrays. Data is written
 * synchronously to PostgreSQL via {@link IngestionService}.
 * <p>
 * Only active when ClickHouse is disabled — when ClickHouse is enabled,
 * {@link ChunkIngestionController} takes over the {@code /executions} mapping.
 */
@RestController
@RequestMapping("/api/v1/data")
@ConditionalOnMissingBean(ChunkAccumulator.class)
@Tag(name = "Ingestion", description = "Data ingestion endpoints")
public class ExecutionController {

    private final IngestionService ingestionService;
    private final AgentRegistryService registryService;
    private final ObjectMapper objectMapper;

    public ExecutionController(IngestionService ingestionService,
                               AgentRegistryService registryService,
                               ObjectMapper objectMapper) {
        this.ingestionService = ingestionService;
        this.registryService = registryService;
        this.objectMapper = objectMapper;
    }

    @PostMapping("/executions")
    @Operation(summary = "Ingest route execution data",
            description = "Accepts a single RouteExecution or an array of RouteExecutions")
    @ApiResponse(responseCode = "202", description = "Data accepted for processing")
    public ResponseEntity<Void> ingestExecutions(@RequestBody String body) throws JsonProcessingException {
        String instanceId = extractAgentId();
        String applicationId = resolveApplicationId(instanceId);
        List<RouteExecution> executions = parsePayload(body);

        for (RouteExecution execution : executions) {
            ingestionService.ingestExecution(instanceId, applicationId, execution);
        }

        return ResponseEntity.accepted().build();
    }

    private String extractAgentId() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return auth != null ? auth.getName() : "";
    }

    private String resolveApplicationId(String instanceId) {
        AgentInfo agent = registryService.findById(instanceId);
        return agent != null ? agent.applicationId() : "";
    }

    private List<RouteExecution> parsePayload(String body) throws JsonProcessingException {
        String trimmed = body.strip();
        if (trimmed.startsWith("[")) {
            return objectMapper.readValue(trimmed, new TypeReference<>() {});
        } else {
            RouteExecution single = objectMapper.readValue(trimmed, RouteExecution.class);
            return List.of(single);
        }
    }
}
