package com.magistr.app.controller;

import com.magistr.app.config.auth.AuthContext;
import com.magistr.app.config.auth.AuthenticatedUser;
import com.magistr.app.config.auth.ClientIpResolver;
import com.magistr.app.config.auth.LoginRateLimitService;
import com.magistr.app.config.tenant.TenantContext;
import com.magistr.app.dto.LoginRequest;
import com.magistr.app.dto.LoginResponse;
import com.magistr.app.model.Role;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpServletRequest;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class AuthControllerTest {

    @AfterEach
    void clearAuthContext() {
        AuthContext.clear();
        TenantContext.clear();
    }

    @Test
    void meAllowsNullDepartmentId() {
        AuthController controller = new AuthController(null, null, null, null, null);
        AuthContext.setCurrentUser(new AuthenticatedUser(10L, "admin", Role.ADMIN, null));

        ResponseEntity<?> response = controller.me();

        assertThat(response.getStatusCode().value()).isEqualTo(200);
        assertThat(response.getBody()).isInstanceOf(Map.class);
        @SuppressWarnings("unchecked")
        Map<String, Object> body = (Map<String, Object>) response.getBody();
        assertThat(body).containsEntry("userId", 10L);
        assertThat(body).containsEntry("username", "admin");
        assertThat(body).containsEntry("role", "ADMIN");
        assertThat(body).containsKey("departmentId");
        assertThat(body.get("departmentId")).isNull();
    }

    @Test
    void loginReturnsTooManyRequestsAndRetryAfterWhenKeyIsBlocked() {
        LoginRateLimitService rateLimitService = mock(LoginRateLimitService.class);
        ClientIpResolver clientIpResolver = mock(ClientIpResolver.class);
        MockHttpServletRequest servletRequest = new MockHttpServletRequest();
        LoginRequest loginRequest = new LoginRequest();
        loginRequest.setUsername("admin");
        loginRequest.setPassword("неверный-пароль");
        TenantContext.setCurrentTenant("tenant");
        when(clientIpResolver.resolve(servletRequest)).thenReturn("198.51.100.7");
        when(rateLimitService.authenticate(
                "tenant", "admin", "неверный-пароль", "198.51.100.7"
        )).thenReturn(new LoginRateLimitService.AuthenticationDecision(
                LoginRateLimitService.AuthenticationDecision.Status.BLOCKED,
                null,
                73
        ));
        AuthController controller = new AuthController(
                rateLimitService, clientIpResolver, null, null, null
        );

        ResponseEntity<LoginResponse> response = controller.login(loginRequest, servletRequest);

        assertThat(response.getStatusCode().value()).isEqualTo(429);
        assertThat(response.getHeaders().getFirst(HttpHeaders.RETRY_AFTER)).isEqualTo("73");
        assertThat(response.getBody()).isNotNull();
        assertThat(response.getBody().isSuccess()).isFalse();
        assertThat(response.getBody().getMessage())
                .isEqualTo("Слишком много попыток входа. Повторите позже");
    }
}
