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 java.time.Instant;
import java.util.List;

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

/**
 * Integration test verifying that {@code users.token_revoked_before} is honoured
 * by {@link JwtAuthenticationFilter}. Regression for the prefix-mismatch bug
 * where the filter looked up the JWT subject ({@code user:alice}) against
 * {@code users.user_id} (bare {@code alice}), so revocation never fired.
 */
class JwtRevocationIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private JwtService jwtService;

    @Autowired
    private UserRepository userRepository;

    @AfterEach
    void cleanup() {
        userRepository.delete("revoke-me");
        userRepository.delete("never-revoked");
    }

    @Test
    void revokedTokenIsRejectedOnAuthenticatedRequest() {
        userRepository.upsert(new UserInfo(
                "revoke-me", "local", "", "Revoke Me", Instant.now()));
        String accessToken = jwtService.createAccessToken(
                "user:revoke-me", "user", List.of("VIEWER"));

        ResponseEntity<String> before = call(accessToken);
        assertThat(before.getStatusCode()).isEqualTo(HttpStatus.OK);

        userRepository.revokeTokensBefore("revoke-me", Instant.now().plusSeconds(1));

        ResponseEntity<String> after = call(accessToken);
        assertThat(after.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
    }

    @Test
    void unrevokedUserTokenIsAccepted() {
        userRepository.upsert(new UserInfo(
                "never-revoked", "local", "", "Never Revoked", Instant.now()));
        String accessToken = jwtService.createAccessToken(
                "user:never-revoked", "user", List.of("VIEWER"));

        ResponseEntity<String> resp = call(accessToken);
        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private ResponseEntity<String> call(String accessToken) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(accessToken);
        return restTemplate.exchange(
                "/api/v1/auth/me",
                HttpMethod.GET,
                new HttpEntity<>(headers),
                String.class);
    }
}
