package com.saas.shared.interceptor;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.http.HttpStatus;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = {
    "resilience4j.ratelimiter.instances.auth.limitForPeriod=3",
    "resilience4j.ratelimiter.instances.auth.limitRefreshPeriod=1m"
})
@DisplayName("Rate Limiter Integration Tests")
public class RateLimiterIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    private static final String LOGIN_ENDPOINT = "/api/auth/login";

    @BeforeEach
    void setUp() {
        // Reset rate limiter state between tests if needed
    }

    @Test
    @DisplayName("Rate limiter should allow requests within limit")
    void testRateLimitAllowedRequests() throws Exception {
        String payload = """
            {
              "email": "test@example.com",
              "password": "TestPassword123!"
            }
            """;

        // First 3 requests should succeed (status 200 or 401 depending on auth, but not 429)
        for (int i = 0; i < 3; i++) {
            final int requestNum = i + 1;
            mockMvc.perform(post(LOGIN_ENDPOINT)
                    .contentType("application/json")
                    .content(payload))
                    .andExpect(result -> {
                        int status = result.getResponse().getStatus();
                        // Should not be 429 (Too Many Requests)
                        if (status == 429) {
                            throw new AssertionError("Request " + requestNum + " was rate limited (status 429)");
                        }
                    });
        }
    }

    @Test
    @DisplayName("Rate limiter should return 429 after limit exceeded")
    void testRateLimitExceeded() throws Exception {
        String payload = """
            {
              "email": "test@example.com",
              "password": "TestPassword123!"
            }
            """;

        // Exceed limit (4th request when limit is 3)
        for (int i = 0; i < 4; i++) {
            mockMvc.perform(post(LOGIN_ENDPOINT)
                    .contentType("application/json")
                    .content(payload));
        }

        // 5th request should definitely be rate limited
        mockMvc.perform(post(LOGIN_ENDPOINT)
                .contentType("application/json")
                .content(payload))
                .andExpect(status().isTooManyRequests());
    }

    @Test
    @DisplayName("Rate limiter should include Retry-After header on 429")
    void testRateLimiterRetryAfterHeader() throws Exception {
        String payload = """
            {
              "email": "test@example.com",
              "password": "TestPassword123!"
            }
            """;

        // Exceed limit
        for (int i = 0; i < 4; i++) {
            mockMvc.perform(post(LOGIN_ENDPOINT)
                    .contentType("application/json")
                    .content(payload));
        }

        // Next request should have Retry-After header
        mockMvc.perform(post(LOGIN_ENDPOINT)
                .contentType("application/json")
                .content(payload))
                .andExpect(status().isTooManyRequests())
                .andExpect(header().exists("Retry-After"));
    }
}
