package com.cameleer.server.app.controller;

import com.cameleer.server.app.AbstractPostgresIT;
import com.cameleer.server.app.TestSecurityHelper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.Map;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

/**
 * POST /api/v1/data/executions is owned by ChunkIngestionController (the
 * legacy ExecutionController is @ConditionalOnMissingBean(ChunkAccumulator)
 * and never binds). All payloads here are ExecutionChunk envelopes.
 */
class ExecutionControllerIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private TestSecurityHelper securityHelper;

    private final ObjectMapper objectMapper = new ObjectMapper();

    private HttpHeaders authHeaders;
    private HttpHeaders viewerHeaders;

    @BeforeEach
    void setUp() {
        // Lift max_agents cap so this IT (which registers an agent) isn't gated by license
        // enforcement. Cap behaviour itself is exercised by AgentCapEnforcementIT.
        securityHelper.installSyntheticUnsignedLicense(Map.of("max_agents", 100));
        String jwt = securityHelper.registerTestAgent("test-agent-execution-it");
        authHeaders = securityHelper.authHeaders(jwt);
        viewerHeaders = securityHelper.authHeadersNoBody(securityHelper.viewerToken());
    }

    @AfterEach
    void tearDown() {
        securityHelper.clearTestLicense();
    }

    @Test
    void postSingleExecution_returns202() {
        String json = """
                {
                  "exchangeId": "exchange-1",
                  "applicationId": "test-group",
                  "instanceId": "test-agent-execution-it",
                  "routeId": "route-1",
                  "correlationId": "corr-1",
                  "status": "COMPLETED",
                  "startTime": "2026-03-11T10:00:00Z",
                  "endTime": "2026-03-11T10:00:01Z",
                  "durationMs": 1000,
                  "chunkSeq": 0,
                  "final": true,
                  "processors": []
                }
                """;

        ResponseEntity<String> response = restTemplate.postForEntity(
                "/api/v1/data/executions",
                new HttpEntity<>(json, authHeaders),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
    }

    @Test
    void postArrayOfExecutions_returns202() {
        String json = """
                [{
                  "exchangeId": "exchange-2",
                  "applicationId": "test-group",
                  "instanceId": "test-agent-execution-it",
                  "routeId": "route-2",
                  "status": "COMPLETED",
                  "startTime": "2026-03-11T10:00:00Z",
                  "endTime": "2026-03-11T10:00:01Z",
                  "durationMs": 1000,
                  "chunkSeq": 0,
                  "final": true,
                  "processors": []
                },
                {
                  "exchangeId": "exchange-3",
                  "applicationId": "test-group",
                  "instanceId": "test-agent-execution-it",
                  "routeId": "route-3",
                  "status": "FAILED",
                  "startTime": "2026-03-11T10:00:00Z",
                  "endTime": "2026-03-11T10:00:02Z",
                  "durationMs": 2000,
                  "errorMessage": "Something went wrong",
                  "chunkSeq": 0,
                  "final": true,
                  "processors": []
                }]
                """;

        ResponseEntity<String> response = restTemplate.postForEntity(
                "/api/v1/data/executions",
                new HttpEntity<>(json, authHeaders),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
    }

    @Test
    void postExecution_dataAppearsAfterFlush() {
        String json = """
                {
                  "exchangeId": "flush-exchange-1",
                  "applicationId": "test-group",
                  "instanceId": "test-agent-execution-it",
                  "routeId": "flush-test-route",
                  "correlationId": "flush-corr-1",
                  "status": "COMPLETED",
                  "startTime": "2026-03-11T10:00:00Z",
                  "endTime": "2026-03-11T10:00:01Z",
                  "durationMs": 1000,
                  "chunkSeq": 0,
                  "final": true,
                  "processors": []
                }
                """;

        restTemplate.postForEntity(
                "/api/v1/data/executions",
                new HttpEntity<>(json, authHeaders),
                String.class);

        // Executions live in ClickHouse; drive the visibility check through
        // the REST search API (env-scoped), never through raw SQL.
        await().atMost(15, SECONDS).untilAsserted(() -> {
            ResponseEntity<String> r = restTemplate.exchange(
                    "/api/v1/environments/default/executions?correlationId=flush-corr-1",
                    HttpMethod.GET,
                    new HttpEntity<>(viewerHeaders),
                    String.class);
            assertThat(r.getStatusCode()).isEqualTo(HttpStatus.OK);
            JsonNode body = objectMapper.readTree(r.getBody());
            assertThat(body.get("total").asLong()).isGreaterThanOrEqualTo(1);
        });
    }

    @Test
    void postExecution_unknownFieldsAccepted() {
        String json = """
                {
                  "exchangeId": "exchange-unk",
                  "applicationId": "test-group",
                  "instanceId": "test-agent-execution-it",
                  "routeId": "route-unk",
                  "status": "COMPLETED",
                  "startTime": "2026-03-11T10:00:00Z",
                  "durationMs": 500,
                  "chunkSeq": 0,
                  "final": true,
                  "unknownField": "should-be-ignored",
                  "anotherUnknown": 42,
                  "processors": []
                }
                """;

        ResponseEntity<String> response = restTemplate.postForEntity(
                "/api/v1/data/executions",
                new HttpEntity<>(json, authHeaders),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
    }
}
