package com.codebyte.api.auth;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.codebyte.api.support.AbstractPostgresIT;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;

/**
 * Rate limiting on {@code /auth/**}. A capacity of 3 (no refill during the test) trips on the 4th.
 */
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(
        properties = {
            "app.rate-limit.enabled=true",
            "app.rate-limit.capacity=3",
            "app.rate-limit.refill-period=1h"
        })
class RateLimitingIT extends AbstractPostgresIT {

    @Autowired private MockMvc mockMvc;

    private int loginStatus() throws Exception {
        return mockMvc.perform(
                        post("/api/v1/auth/login")
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(
                                        "{\"email\":\"nobody@example.com\",\"password\":\"somepassword\"}"))
                .andReturn()
                .getResponse()
                .getStatus();
    }

    @Test
    void should_reject_requests_over_the_limit_with_429() throws Exception {
        // Capacity 3: first three are allowed (401 bad creds), fourth is rate-limited.
        for (int i = 0; i < 3; i++) {
            org.assertj.core.api.Assertions.assertThat(loginStatus()).isEqualTo(401);
        }
        mockMvc.perform(
                        post("/api/v1/auth/login")
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(
                                        "{\"email\":\"nobody@example.com\",\"password\":\"somepassword\"}"))
                .andExpect(status().isTooManyRequests())
                .andExpect(jsonPath("$.code", Matchers.is("RATE_LIMITED")));
    }
}
