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

import com.fasterxml.jackson.databind.JsonNode;
import com.ycwl.basic.puzzle.fill.enums.ConditionType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 机位数量匹配策略（大于等于匹配）
 *
 * <p>支持两种匹配模式：</p>
 * <ul>
 *   <li>模式1：全局数量匹配 - 只指定 deviceCount，匹配所有机位的数量 ≥ deviceCount</li>
 *   <li>模式2：指定列表数量匹配 - 同时指定 deviceCount + deviceIds，从指定列表中过滤并匹配数量 ≥ deviceCount</li>
 * </ul>
 *
 * <p>配置示例：</p>
 * <pre>
 * // 模式1：全局数量匹配（大于等于）
 * {
 *   "deviceCount": 4
 * }
 * // 匹配：用户有4个或更多机位时匹配成功
 *
 * // 模式2：指定列表数量匹配（大于等于）
 * {
 *   "deviceCount": 2,
 *   "deviceIds": [200, 300, 400]
 * }
 * // 匹配：从列表中过滤出≥2个机位时匹配成功，只取前2个供数据源使用
 * </pre>
 *
 * <p>模式2匹配逻辑：</p>
 * <ul>
 *   <li>从 deviceIds 列表中过滤出实际存在的机位</li>
 *   <li>保持配置顺序(不按 deviceId 排序)</li>
 *   <li>判断过滤后的数量是否 ≥ deviceCount</li>
 *   <li>匹配成功后,只取前 deviceCount 个机位存入 context.extra,供数据源解析使用</li>
 * </ul>
 *
 * @author Claude
 * @since 2025-01-20
 */
@Slf4j
@Component
public class DeviceCountConditionStrategy implements ConditionStrategy {

    @Override
    public boolean evaluate(JsonNode conditionValue, ConditionContext context) {
        if (conditionValue == null || !conditionValue.has("deviceCount")) {
            log.warn("DEVICE_COUNT条件缺少deviceCount字段");
            return false;
        }

        int expectedCount = conditionValue.get("deviceCount").asInt();
        if (expectedCount <= 0) {
            log.warn("deviceCount必须大于0, 当前值: {}", expectedCount);
            return false;
        }

        // 检查是否指定了 deviceIds（模式2）
        if (conditionValue.has("deviceIds")) {
            return evaluateWithDeviceIdList(conditionValue, context, expectedCount);
        } else {
            // 模式1：全局数量匹配
            return evaluateGlobalCount(context, expectedCount);
        }
    }

    /**
     * 模式1：全局数量匹配（大于等于）
     */
    private boolean evaluateGlobalCount(ConditionContext context, int expectedCount) {
        Integer actualCount = context.getDeviceCount();
        if (actualCount == null) {
            log.debug("上下文中没有机位数量信息");
            return false;
        }

        boolean matched = actualCount >= expectedCount;
        if (matched) {
            log.info("DEVICE_COUNT全局匹配成功: 最小数量={}, 实际数量={}", expectedCount, actualCount);
        } else {
            log.debug("DEVICE_COUNT全局匹配失败: 最小数量={}, 实际数量={}", expectedCount, actualCount);
        }
        return matched;
    }

    /**
     * 模式2：指定列表数量匹配（大于等于，只取前N个）
     */
    private boolean evaluateWithDeviceIdList(JsonNode conditionValue, ConditionContext context, int expectedCount) {
        // 1. 读取配置的 deviceIds 列表
        JsonNode deviceIdsNode = conditionValue.get("deviceIds");
        if (!deviceIdsNode.isArray()) {
            log.warn("deviceIds字段必须是数组");
            return false;
        }

        List<Long> requiredDeviceIds = new ArrayList<>();
        deviceIdsNode.forEach(node -> requiredDeviceIds.add(node.asLong()));

        if (requiredDeviceIds.isEmpty()) {
            log.warn("deviceIds数组为空");
            return false;
        }

        // 2. 获取上下文中的机位列表
        List<Long> contextDeviceIds = context.getDeviceIds();
        if (contextDeviceIds == null || contextDeviceIds.isEmpty()) {
            log.debug("上下文中没有机位ID列表");
            return false;
        }

        // 3. 按配置顺序过滤出实际存在的机位
        List<Long> matchedDeviceIds = requiredDeviceIds.stream()
                .filter(contextDeviceIds::contains)
                .collect(Collectors.toList()); // 保持配置顺序,不排序

        // 4. 判断是否满足最小数量要求（大于等于）
        boolean matched = matchedDeviceIds.size() >= expectedCount;

        if (matched) {
            // 5. 只取前 expectedCount 个机位存入 context.extra
            List<Long> limitedDeviceIds = matchedDeviceIds.stream()
                    .limit(expectedCount)
                    .collect(Collectors.toList());

            Map<String, Object> extra = new HashMap<>();
            extra.put("filteredDeviceIds", limitedDeviceIds);
            context.setExtra(extra);

            log.info("DEVICE_COUNT列表匹配成功: 配置列表={}, 过滤后={}, 最小数量={}, 实际数量={}, 取前{}个={}",
                    requiredDeviceIds, matchedDeviceIds, expectedCount, matchedDeviceIds.size(), expectedCount, limitedDeviceIds);
        } else {
            log.debug("DEVICE_COUNT列表匹配失败: 配置列表={}, 过滤后={}, 最小数量={}, 实际数量={}",
                    requiredDeviceIds, matchedDeviceIds, expectedCount, matchedDeviceIds.size());
        }

        return matched;
    }

    @Override
    public String getSupportedType() {
        return ConditionType.DEVICE_COUNT.getCode();
    }
}
