package io.cameleer.server.app.license;

import io.cameleer.server.app.AbstractPostgresIT;
import io.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.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

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

/**
 * Verifies that the {@code max_jar_retention_count} cap is enforced at
 * {@code PUT /api/v1/admin/environments/{envSlug}/jar-retention}. The default tier cap is 3,
 * so no synthetic license is installed — the rejection is exercised against the baseline.
 *
 * <p>Returns 422 UNPROCESSABLE_ENTITY (not 403) because retention is a value-out-of-range
 * rejection, not a creation-quota rejection — so {@code LicenseExceptionAdvice} is intentionally
 * bypassed in favour of {@link org.springframework.web.server.ResponseStatusException}.
 */
class RetentionCapEnforcementIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestSecurityHelper securityHelper;

    private String adminJwt;

    @BeforeEach
    void setUp() {
        adminJwt = securityHelper.adminToken();
        // Defensive: a sibling IT may have left a license installed.
        securityHelper.clearTestLicense();
        // Strip non-default envs (and FK dependents) so we land on a clean baseline.
        jdbcTemplate.update("DELETE FROM deployments");
        jdbcTemplate.update("DELETE FROM app_versions");
        jdbcTemplate.update("DELETE FROM apps");
        jdbcTemplate.update("DELETE FROM environments WHERE slug != 'default'");
    }

    @AfterEach
    void tearDown() {
        securityHelper.clearTestLicense();
        jdbcTemplate.update("DELETE FROM deployments");
        jdbcTemplate.update("DELETE FROM app_versions");
        jdbcTemplate.update("DELETE FROM apps");
        jdbcTemplate.update("DELETE FROM environments WHERE slug != 'default'");
    }

    @Test
    void putJarRetention_aboveCap_returns422() throws Exception {
        // Default tier cap = 3; request 30.
        String body = """
                {"jarRetentionCount": 30}
                """;
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/environments/default/jar-retention", HttpMethod.PUT,
                new HttpEntity<>(body, securityHelper.authHeaders(adminJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY);
        // ResponseStatusException renders into Spring Boot's default error JSON; the reason
        // appears in the "message" field (or the body somewhere). Don't pin to a specific shape;
        // just verify the diagnostic text reached the wire.
        String responseBody = response.getBody() == null ? "" : response.getBody();
        assertThat(responseBody)
                .containsAnyOf("max_jar_retention_count", "license cap");
    }

    @Test
    void putJarRetention_atCap_returns200() throws Exception {
        // Default tier cap = 3; request exactly 3.
        String body = """
                {"jarRetentionCount": 3}
                """;
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/environments/default/jar-retention", HttpMethod.PUT,
                new HttpEntity<>(body, securityHelper.authHeaders(adminJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode envBody = objectMapper.readTree(response.getBody());
        assertThat(envBody.path("jarRetentionCount").asInt()).isEqualTo(3);
    }

    @Test
    void putJarRetention_nullValue_returns200_unlimited() throws Exception {
        // null = unlimited (no cap check fires). Important regression: ensure the cap-check
        // guard remains a `requested != null` short-circuit and doesn't reject unlimited mode.
        String body = """
                {"jarRetentionCount": null}
                """;
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/environments/default/jar-retention", HttpMethod.PUT,
                new HttpEntity<>(body, securityHelper.authHeaders(adminJwt)),
                String.class);

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