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.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;

class DatabaseAdminControllerIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestSecurityHelper securityHelper;

    private String adminJwt;
    private String viewerJwt;

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

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

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.get("connected").asBoolean()).isTrue();
        assertThat(body.get("version").asText()).contains("PostgreSQL");
        assertThat(body.has("schema")).isTrue();
    }

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

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

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

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.has("activeConnections")).isTrue();
        assertThat(body.has("idleConnections")).isTrue();
        assertThat(body.get("maxPoolSize").asInt()).isGreaterThan(0);
    }

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

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

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

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

    @Test
    void killQuery_unknownPid_returns404() {
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/admin/database/queries/999999/kill", HttpMethod.POST,
                new HttpEntity<>(securityHelper.authHeadersNoBody(adminJwt)),
                String.class);

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