package com.cameleer.server.app.security;

import com.cameleer.server.app.AbstractPostgresIT;
import com.cameleer.server.app.TestSecurityHelper;
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 the SecurityFilterChain correctly
 * protects endpoints and allows public access where configured.
 */
class SecurityFilterIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private TestSecurityHelper securityHelper;

    private String viewerJwt;

    @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));
        securityHelper.registerTestAgent("test-agent-security-filter-it");
        viewerJwt = securityHelper.viewerToken();
    }

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

    @Test
    void protectedEndpoint_withoutJwt_returns401or403() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("X-Cameleer-Protocol-Version", "1");

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/agents",
                HttpMethod.GET,
                new HttpEntity<>(headers),
                String.class);

        assertThat(response.getStatusCode().value()).isIn(401, 403);
    }

    @Test
    void protectedEndpoint_withValidJwt_returns200() {
        // Agent list moved from flat /api/v1/agents to env-scoped path.
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/environments/default/agents",
                HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(viewerJwt)),
                String.class);

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

    @Test
    void healthEndpoint_withoutJwt_returns200() {
        ResponseEntity<String> response = restTemplate.getForEntity(
                "/api/v1/health", String.class);

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

    @Test
    void dataEndpoint_withoutJwt_returns401or403() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("X-Cameleer-Protocol-Version", "1");

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

        assertThat(response.getStatusCode().value()).isIn(401, 403);
    }

    @Test
    void protectedEndpoint_withExpiredJwt_returns401or403() {
        // An invalid/malformed token should be rejected
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer expired.invalid.token");
        headers.set("X-Cameleer-Protocol-Version", "1");

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/agents",
                HttpMethod.GET,
                new HttpEntity<>(headers),
                String.class);

        assertThat(response.getStatusCode().value()).isIn(401, 403);
    }

    @Test
    void protectedEndpoint_withMalformedJwt_returns401or403() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer not-a-jwt");
        headers.set("X-Cameleer-Protocol-Version", "1");

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/agents",
                HttpMethod.GET,
                new HttpEntity<>(headers),
                String.class);

        assertThat(response.getStatusCode().value()).isIn(401, 403);
    }
}
