package com.mosquito.project.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mosquito.project.persistence.entity.RiskRuleEntity;
import com.mosquito.project.persistence.repository.RiskAlertRepository;
import com.mosquito.project.persistence.repository.RiskRuleRepository;
import com.mosquito.project.permission.SysUserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

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

@ExtendWith(MockitoExtension.class)
@DisplayName("风控服务测试")
class RiskServiceTest {

    @Mock
    private RiskAlertRepository alertRepository;

    @Mock
    private RiskRuleRepository ruleRepository;

    @Mock
    private SysUserService sysUserService;

    @Mock
    private AuditService auditService;

    @Mock
    private StringRedisTemplate redisTemplate;

    @Mock
    private ValueOperations<String, String> valueOperations;

    @Spy
    private ObjectMapper objectMapper = new ObjectMapper();

    @InjectMocks
    private RiskService riskService;

    private RiskRuleEntity testRule;

    @BeforeEach
    void setUp() {
        testRule = new RiskRuleEntity();
        testRule.setId(1L);
        testRule.setName("Test Rule");
        testRule.setRiskType("CALLBACK");
        testRule.setConditionExpr("count > 100");
        testRule.setAction("LIMIT");
        testRule.setActionParams("{\"maxCalls\": 10}");
        testRule.setStatus("ENABLED");
        testRule.setPriority(1);
        testRule.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
        testRule.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
    }

    @Test
    @DisplayName("测试保存待审批的规则更新")
    void testSavePendingRuleUpdate() {
        // Arrange
        Map<String, Object> request = new HashMap<>();
        request.put("name", "Updated Rule Name");
        request.put("type", "CALLBACK");
        request.put("condition", "count > 200");
        request.put("action", "BAN");
        request.put("priority", 5);

        when(ruleRepository.findById(1L)).thenReturn(Optional.of(testRule));
        when(ruleRepository.save(any(RiskRuleEntity.class))).thenReturn(testRule);

        // Act
        boolean result = riskService.savePendingRuleUpdate(1L, request);

        // Assert
        assertTrue(result);
        verify(ruleRepository).save(argThat(entity -> {
            assertEquals("PENDING_APPROVAL_UPDATE", entity.getStatus());
            assertNotNull(entity.getPendingUpdate());
            return true;
        }));
    }

    @Test
    @DisplayName("测试审批通过后应用规则更新 - 新建审批")
    void testApplyPendingRule_NewApproval() {
        // Arrange
        testRule.setStatus("PENDING_APPROVAL");
        when(ruleRepository.findById(1L)).thenReturn(Optional.of(testRule));
        when(ruleRepository.save(any(RiskRuleEntity.class))).thenReturn(testRule);

        // Act
        boolean result = riskService.applyPendingRule(1L);

        // Assert
        assertTrue(result);
        verify(ruleRepository).save(argThat(entity -> {
            assertEquals("ENABLED", entity.getStatus());
            return true;
        }));
    }

    @Test
    @DisplayName("测试审批通过后应用规则更新 - 更新审批")
    void testApplyPendingRule_UpdateApproval() {
        // Arrange
        testRule.setStatus("PENDING_APPROVAL_UPDATE");
        String pendingUpdateJson = "{\"name\":\"Updated Rule\",\"type\":\"CALLBACK\",\"condition\":\"count > 200\",\"action\":\"BAN\",\"priority\":5}";
        testRule.setPendingUpdate(pendingUpdateJson);

        when(ruleRepository.findById(1L)).thenReturn(Optional.of(testRule));
        when(ruleRepository.save(any(RiskRuleEntity.class))).thenReturn(testRule);

        // Act
        boolean result = riskService.applyPendingRule(1L);

        // Assert
        assertTrue(result);
        verify(ruleRepository).save(argThat(entity -> {
            assertEquals("ENABLED", entity.getStatus());
            assertNull(entity.getPendingUpdate()); // 更新内容应该被清除
            return true;
        }));
    }

    @Test
    @DisplayName("测试审批通过后应用规则更新 - 不存在的规则")
    void testApplyPendingRule_NotFound() {
        // Arrange
        when(ruleRepository.findById(999L)).thenReturn(Optional.empty());

        // Act
        boolean result = riskService.applyPendingRule(999L);

        // Assert
        assertFalse(result);
    }

    @Test
    @DisplayName("测试保存待审批的规则更新 - 不存在的规则")
    void testSavePendingRuleUpdate_NotFound() {
        // Arrange
        Map<String, Object> request = new HashMap<>();
        request.put("name", "Updated Rule Name");

        when(ruleRepository.findById(999L)).thenReturn(Optional.empty());

        // Act
        boolean result = riskService.savePendingRuleUpdate(999L, request);

        // Assert
        assertFalse(result);
    }
}
