package com.ycwl.basic.puzzle.fill.condition;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 机位数量匹配策略测试（大于等于匹配）
 */
@DisplayName("机位数量匹配策略测试（大于等于匹配）")
class DeviceCountConditionStrategyTest {

    private DeviceCountConditionStrategy strategy;
    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        strategy = new DeviceCountConditionStrategy();
        objectMapper = new ObjectMapper();
    }

    @Test
    @DisplayName("应该返回正确的支持类型")
    void shouldReturnCorrectSupportedType() {
        assertEquals("DEVICE_COUNT", strategy.getSupportedType());
    }

    @Test
    @DisplayName("当机位数量大于等于期望时应该返回true")
    void shouldReturnTrueWhenDeviceCountMatches() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 4}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(4)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertTrue(result);
    }

    @Test
    @DisplayName("模式1：当机位数量大于期望时应该返回true")
    void shouldReturnTrueWhenDeviceCountGreaterThanExpected() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 4}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(5)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertTrue(result);
    }

    @Test
    @DisplayName("当机位数量小于期望时应该返回false")
    void shouldReturnFalseWhenDeviceCountDoesNotMatch() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 4}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(2)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("当conditionValue为null时应该返回false")
    void shouldReturnFalseWhenConditionValueIsNull() {
        // Given
        ConditionContext context = ConditionContext.builder()
                .deviceCount(4)
                .build();

        // When
        boolean result = strategy.evaluate(null, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("当conditionValue缺少deviceCount字段时应该返回false")
    void shouldReturnFalseWhenDeviceCountFieldIsMissing() throws Exception {
        // Given
        String conditionValueJson = "{\"otherField\": 4}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(4)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("当context中deviceCount为null时应该返回false")
    void shouldReturnFalseWhenContextDeviceCountIsNull() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 4}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(null)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("应该支持deviceCount为0的情况")
    void shouldSupportZeroDeviceCount() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 0}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(0)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result); // 修改：deviceCount必须大于0
    }

    // ==================== 模式2：指定列表数量匹配（大于等于） ====================

    @Test
    @DisplayName("模式2：当指定列表中恰好有期望数量的机位时应该返回true")
    void shouldReturnTrueWhenDeviceIdListMatchesCount() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [200, 300, 400]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L, 500L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(3)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertTrue(result);
        assertNotNull(context.getExtra());
        assertTrue(context.getExtra().containsKey("filteredDeviceIds"));

        @SuppressWarnings("unchecked")
        List<Long> filteredIds = (List<Long>) context.getExtra().get("filteredDeviceIds");
        assertEquals(2, filteredIds.size());
        assertEquals(Arrays.asList(200L, 300L), filteredIds); // 保持配置顺序
    }

    @Test
    @DisplayName("模式2：当指定列表中机位数量大于期望时应该返回true，且只取前N个")
    void shouldReturnTrueWhenDeviceIdListCountExceedsExpected() throws Exception {
        // Given - 配置需要2个，实际过滤出3个
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [200, 300, 400]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L, 400L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(3)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertTrue(result);
        assertNotNull(context.getExtra());

        @SuppressWarnings("unchecked")
        List<Long> filteredIds = (List<Long>) context.getExtra().get("filteredDeviceIds");
        assertEquals(2, filteredIds.size()); // 只取前2个
        assertEquals(Arrays.asList(200L, 300L), filteredIds); // 按配置顺序取前2个，不包含400
    }

    @Test
    @DisplayName("模式2：当指定列表中的机位数量不足时应该返回false")
    void shouldReturnFalseWhenDeviceIdListCountInsufficient() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 3, \"deviceIds\": [200, 300, 400]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L, 500L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(3)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("模式2：应该保持配置的机位顺序，不排序，且只取前N个")
    void shouldPreserveDeviceIdOrderInMode2() throws Exception {
        // Given - 配置顺序为 400, 200, 300，需要2个
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [400, 200, 300]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L, 400L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(3)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertTrue(result);

        @SuppressWarnings("unchecked")
        List<Long> filteredIds = (List<Long>) context.getExtra().get("filteredDeviceIds");
        assertEquals(2, filteredIds.size());
        assertEquals(Arrays.asList(400L, 200L), filteredIds); // 保持配置顺序，只取前2个
    }

    @Test
    @DisplayName("模式2：当deviceIds为空数组时应该返回false")
    void shouldReturnFalseWhenDeviceIdsIsEmptyArray() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": []}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(2)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("模式2：当deviceIds不是数组类型时应该返回false")
    void shouldReturnFalseWhenDeviceIdsIsNotArray() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": \"not-an-array\"}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(2)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("模式2：当context中没有deviceIds时应该返回false")
    void shouldReturnFalseWhenContextDeviceIdsIsNull() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [200, 300]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(2)
                .deviceIds(null)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("模式2：当context中deviceIds为空列表时应该返回false")
    void shouldReturnFalseWhenContextDeviceIdsIsEmpty() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [200, 300]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        ConditionContext context = ConditionContext.builder()
                .deviceCount(2)
                .deviceIds(Collections.emptyList())
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }

    @Test
    @DisplayName("模式2：当deviceCount为0时应该返回false")
    void shouldReturnFalseWhenDeviceCountIsZeroInMode2() throws Exception {
        // Given
        String conditionValueJson = "{\"deviceCount\": 0, \"deviceIds\": [200, 300]}";
        JsonNode conditionValue = objectMapper.readTree(conditionValueJson);

        List<Long> contextDeviceIds = Arrays.asList(200L, 300L);
        ConditionContext context = ConditionContext.builder()
                .deviceCount(2)
                .deviceIds(contextDeviceIds)
                .build();

        // When
        boolean result = strategy.evaluate(conditionValue, context);

        // Then
        assertFalse(result);
    }
}
