package com.dora.service;

import com.dora.service.impl.IdentityVerifyLimitServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

/**
 * 实名认证限制服务测试类
 */
public class IdentityVerifyLimitServiceTest {

    @Mock
    private RedisTemplate<String, String> redisTemplate;

    @Mock
    private ValueOperations<String, String> valueOperations;

    private IdentityVerifyLimitServiceImpl identityVerifyLimitService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        when(redisTemplate.opsForValue()).thenReturn(valueOperations);
        
        identityVerifyLimitService = new IdentityVerifyLimitServiceImpl(redisTemplate);
        
        // 设置配置值
        ReflectionTestUtils.setField(identityVerifyLimitService, "dailyLimit", 3);
        ReflectionTestUtils.setField(identityVerifyLimitService, "redisKeyPrefix", "identity_verify_daily");
        ReflectionTestUtils.setField(identityVerifyLimitService, "enableLimit", true);
    }

    @Test
    void testCanMakeVerifyRequest_WithinLimit() {
        // 模拟用户今天已请求2次，限制3次
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn("2");
        
        boolean canRequest = identityVerifyLimitService.canMakeVerifyRequest(userId);
        
        assertTrue(canRequest);
        verify(valueOperations).get(contains("identity_verify_daily:123:"));
    }

    @Test
    void testCanMakeVerifyRequest_ExceedsLimit() {
        // 模拟用户今天已请求3次，达到限制
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn("3");
        
        boolean canRequest = identityVerifyLimitService.canMakeVerifyRequest(userId);
        
        assertFalse(canRequest);
    }

    @Test
    void testCanMakeVerifyRequest_FirstRequest() {
        // 模拟用户今天首次请求
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn(null);
        
        boolean canRequest = identityVerifyLimitService.canMakeVerifyRequest(userId);
        
        assertTrue(canRequest);
    }

    @Test
    void testCanMakeVerifyRequest_LimitDisabled() {
        // 禁用限制功能
        ReflectionTestUtils.setField(identityVerifyLimitService, "enableLimit", false);
        
        Long userId = 123L;
        boolean canRequest = identityVerifyLimitService.canMakeVerifyRequest(userId);
        
        assertTrue(canRequest);
        // 应该不会调用Redis
        verify(valueOperations, never()).get(anyString());
    }

    @Test
    void testIncrementVerifyRequest() {
        // 测试增加请求计数
        Long userId = 123L;
        when(valueOperations.increment(anyString())).thenReturn(1L);
        
        identityVerifyLimitService.incrementVerifyRequest(userId);
        
        verify(valueOperations).increment(contains("identity_verify_daily:123:"));
        verify(redisTemplate).expire(anyString(), anyLong(), eq(TimeUnit.SECONDS));
    }

    @Test
    void testGetTodayRequestCount() {
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn("2");
        
        int count = identityVerifyLimitService.getTodayRequestCount(userId);
        
        assertEquals(2, count);
    }

    @Test
    void testGetTodayRequestCount_NoRecord() {
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn(null);
        
        int count = identityVerifyLimitService.getTodayRequestCount(userId);
        
        assertEquals(0, count);
    }

    @Test
    void testGetRemainingRequests() {
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn("1");
        
        int remaining = identityVerifyLimitService.getRemainingRequests(userId);
        
        assertEquals(2, remaining); // 3 - 1 = 2
    }

    @Test
    void testGetRemainingRequests_ExceedsLimit() {
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenReturn("5");
        
        int remaining = identityVerifyLimitService.getRemainingRequests(userId);
        
        assertEquals(0, remaining); // 不能为负数
    }

    @Test
    void testGetDailyLimit() {
        int limit = identityVerifyLimitService.getDailyLimit();
        assertEquals(3, limit);
    }

    @Test
    void testRedisException_ShouldAllowRequest() {
        // 模拟Redis异常
        Long userId = 123L;
        when(valueOperations.get(anyString())).thenThrow(new RuntimeException("Redis连接异常"));
        
        boolean canRequest = identityVerifyLimitService.canMakeVerifyRequest(userId);
        
        // 异常时应该采用宽松策略，允许请求
        assertTrue(canRequest);
    }

    @Test
    void testIncrementVerifyRequest_LimitDisabled() {
        // 禁用限制功能
        ReflectionTestUtils.setField(identityVerifyLimitService, "enableLimit", false);
        
        Long userId = 123L;
        identityVerifyLimitService.incrementVerifyRequest(userId);
        
        // 应该不会调用Redis
        verify(valueOperations, never()).increment(anyString());
    }

    @Test
    void testGetTodayRequestCount_LimitDisabled() {
        // 禁用限制功能
        ReflectionTestUtils.setField(identityVerifyLimitService, "enableLimit", false);
        
        Long userId = 123L;
        int count = identityVerifyLimitService.getTodayRequestCount(userId);
        
        assertEquals(0, count);
        // 应该不会调用Redis
        verify(valueOperations, never()).get(anyString());
    }

    @Test
    void testGetRemainingRequests_LimitDisabled() {
        // 禁用限制功能
        ReflectionTestUtils.setField(identityVerifyLimitService, "enableLimit", false);
        
        Long userId = 123L;
        int remaining = identityVerifyLimitService.getRemainingRequests(userId);
        
        assertEquals(3, remaining); // 功能禁用时返回最大限制数
    }
}