package com.cameleer.server.app.security;

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.MediaType;
import org.springframework.http.ResponseEntity;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * Integration tests verifying that registration returns security credentials
 * and that those credentials can be used to access protected endpoints.
 */
class RegistrationSecurityIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestSecurityHelper securityHelper;

    @BeforeEach
    void setUp() {
        // Lift max_agents cap so this IT (which registers agents per test) isn't gated
        // by license enforcement. Cap behaviour itself is exercised by AgentCapEnforcementIT.
        securityHelper.installSyntheticUnsignedLicense(Map.of("max_agents", 100));
    }

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

    private ResponseEntity<String> registerAgent(String agentId) {
        String json = """
                {
                  "instanceId": "%s",
                  "applicationId": "test-group",
                  "environmentId": "default",
                  "version": "1.0.0",
                  "routeIds": [],
                  "capabilities": {}
                }
                """.formatted(agentId);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("X-Cameleer-Protocol-Version", "1");
        headers.set("Authorization", "Bearer test-bootstrap-token");

        return restTemplate.postForEntity(
                "/api/v1/agents/register",
                new HttpEntity<>(json, headers),
                String.class);
    }

    @Test
    void registrationResponse_containsNonNullServerPublicKey() throws Exception {
        ResponseEntity<String> response = registerAgent("reg-sec-pubkey");
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.get("serverPublicKey").asText())
                .isNotNull()
                .isNotEmpty();
        // Base64-encoded Ed25519 public key should be a reasonable length
        assertThat(body.get("serverPublicKey").asText().length()).isGreaterThan(20);
    }

    @Test
    void registrationResponse_containsAccessAndRefreshTokens() throws Exception {
        ResponseEntity<String> response = registerAgent("reg-sec-tokens");
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.get("accessToken").asText()).isNotEmpty();
        assertThat(body.get("refreshToken").asText()).isNotEmpty();
    }

    @Test
    void accessTokenFromRegistration_canAccessProtectedEndpoints() throws Exception {
        ResponseEntity<String> regResponse = registerAgent("reg-sec-access-test");
        assertThat(regResponse.getStatusCode()).isEqualTo(HttpStatus.OK);

        JsonNode regBody = objectMapper.readTree(regResponse.getBody());
        String accessToken = regBody.get("accessToken").asText();

        // Hit an AGENT-role endpoint (heartbeat) to verify the access token is
        // accepted. Env-scoped read endpoints now require VIEWER+, so the agent
        // token would get 403 there.
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + accessToken);
        headers.set("X-Cameleer-Protocol-Version", "1");

        ResponseEntity<String> response = restTemplate.postForEntity(
                "/api/v1/agents/reg-sec-access-test/heartbeat",
                new HttpEntity<>(headers),
                String.class);

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