package com.cameleer.server.app.controller;

import com.cameleer.server.app.AbstractPostgresIT;
import com.cameleer.server.app.TestSecurityHelper;
import com.cameleer.server.core.admin.AuditCategory;
import com.cameleer.server.core.admin.AuditResult;
import com.cameleer.server.core.admin.AuditService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
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 java.util.Map;

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

class AuditLogControllerIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestSecurityHelper securityHelper;

    @Autowired
    private AuditService auditService;

    private String adminJwt;
    private String viewerJwt;

    @BeforeEach
    void setUp() {
        adminJwt = securityHelper.adminToken();
        viewerJwt = securityHelper.viewerToken();
    }

    @Test
    void getAuditLog_asAdmin_returns200() throws Exception {
        // Insert a test audit entry
        auditService.log("test-admin", "test_action", AuditCategory.CONFIG,
                "test-target", Map.of("key", "value"), AuditResult.SUCCESS, null);

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/audit", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(adminJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.has("items")).isTrue();
        assertThat(body.has("totalCount")).isTrue();
        assertThat(body.get("totalCount").asLong()).isGreaterThanOrEqualTo(1);
    }

    @Test
    void getAuditLog_asViewer_returns403() {
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/audit", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(viewerJwt)),
                String.class);

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

    @Test
    void getAuditLog_withCategoryFilter_returnsFilteredResults() throws Exception {
        auditService.log("filter-test", "infra_action", AuditCategory.INFRA,
                "infra-target", null, AuditResult.SUCCESS, null);

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/audit?category=INFRA", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(adminJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.get("items").isArray()).isTrue();
    }

    @Test
    void getAuditLog_withPagination_respectsPageSize() throws Exception {
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/audit?page=0&size=5", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(adminJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.get("pageSize").asInt()).isEqualTo(5);
    }

    @Test
    void getAuditLog_maxPageSizeEnforced() throws Exception {
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/audit?size=500", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(adminJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.get("pageSize").asInt()).isEqualTo(100);
    }
}
