package io.cameleer.server.app.security;

import io.cameleer.server.app.AbstractPostgresIT;
import io.cameleer.server.core.security.JwtService;
import io.cameleer.server.core.security.UserInfo;
import io.cameleer.server.core.security.UserRepository;
import org.junit.jupiter.api.AfterEach;
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.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;

import java.time.Instant;
import java.util.List;

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

class LogoutControllerIT extends AbstractPostgresIT {

    @Autowired TestRestTemplate restTemplate;
    @Autowired JwtService jwtService;
    @Autowired UserRepository userRepository;
    @Autowired JdbcTemplate jdbc;

    @AfterEach
    void cleanup() {
        userRepository.delete("logout-test");
        jdbc.update("DELETE FROM audit_log WHERE username = ?", "logout-test");
    }

    @Test
    void logoutRevokesTokensAuditsAndRejectsSubsequentCalls() {
        userRepository.upsert(new UserInfo("logout-test", "local", "", "Logout Test", Instant.now()));
        String accessToken = jwtService.createAccessToken("user:logout-test", "user", List.of("VIEWER"));

        HttpHeaders authed = new HttpHeaders();
        authed.setBearerAuth(accessToken);

        ResponseEntity<Void> logoutResp = restTemplate.exchange(
                "/api/v1/auth/logout", HttpMethod.POST, new HttpEntity<>(authed), Void.class);
        assertThat(logoutResp.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);

        Instant revokedAt = jdbc.queryForObject(
                "SELECT token_revoked_before FROM users WHERE user_id = ?",
                (rs, n) -> rs.getTimestamp(1).toInstant(), "logout-test");
        assertThat(revokedAt).isAfter(Instant.now().minusSeconds(10));

        Long auditCount = jdbc.queryForObject(
                "SELECT COUNT(*) FROM audit_log WHERE category = 'AUTH' AND action = 'logout' AND username = ?",
                Long.class, "logout-test");
        assertThat(auditCount).isEqualTo(1L);

        ResponseEntity<String> meResp = restTemplate.exchange(
                "/api/v1/auth/me", HttpMethod.GET, new HttpEntity<>(authed), String.class);
        assertThat(meResp.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
    }

    @Test
    void logoutWithoutTokenReturns204NoOp() {
        ResponseEntity<Void> resp = restTemplate.exchange(
                "/api/v1/auth/logout", HttpMethod.POST, HttpEntity.EMPTY, Void.class);
        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
    }
}
