package com.aps.service.impl;

import com.aps.entity.DiscreteParameterMatrix;
import com.aps.entity.RoutingDiscreteParam;
import com.aps.entity.basic.Entry;
import com.aps.mapper.DiscreteParameterMatrixMapper;
import com.aps.service.DiscreteParameterMatrixService;
import com.aps.service.RoutingDiscreteParamService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class DiscreteParameterMatrixServiceImpl extends ServiceImpl<DiscreteParameterMatrixMapper, DiscreteParameterMatrix> implements DiscreteParameterMatrixService {

    @Autowired
    private RoutingDiscreteParamService _routingDiscreteParamService;

    // 缓存配置
    private static final int MAX_RESULT_CACHE_SIZE = 1000;    // 结果缓存最大容量
    private static final int MAX_MATRIX_CACHE_SIZE = 500;     // 矩阵数据缓存最大容量
    private static final int CLEANUP_INTERVAL = 100;          // 每100次调用清理一次

    // 双缓存：计算结果缓存 + 矩阵数据缓存
    private final ConcurrentHashMap<String, Double> resultCache = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, List<DiscreteParameterMatrix>> matrixDataCache = new ConcurrentHashMap<>();

    // 调用计数器
    private int callCount = 0;

    @Override
    public double getDiscreteParameterMatrixValue(Entry entry, Entry lastEntry) {
        // 参数校验
        cleanCache(resultCache, MAX_RESULT_CACHE_SIZE);


        if (entry == null || lastEntry == null) {
            return 0.0;
        }

        List<RoutingDiscreteParam> firstParams = lastEntry.getDiscreteParameter();
        List<RoutingDiscreteParam> secondParams = entry.getDiscreteParameter();

        if (firstParams == null || secondParams == null || firstParams.isEmpty() || secondParams.isEmpty()) {
            return 0.0;
        }

        // 生成缓存键
        String cacheKey = generateCacheKey(entry, lastEntry, firstParams, secondParams);

        // 使用computeIfAbsent：线程安全，有则返回，无则计算
        double result = resultCache.computeIfAbsent(cacheKey, key -> {
            // 查找匹配参数
            List<RoutingDiscreteParam> matchingParams = findMatchingParams(firstParams, secondParams);
            if (matchingParams.isEmpty()) {
                return 0.0;
            }

            // 获取设备/设备类型ID
            long firstEquipId = lastEntry.getSelectMachineID() != null ? lastEntry.getSelectMachineID() : 0L;
            long secondEquipId = entry.getSelectMachineID() != null ? entry.getSelectMachineID() : 0L;
            long firstEquipTypeId = lastEntry.getEquipTypeID() != null ? lastEntry.getEquipTypeID() : 0L;
            long secondEquipTypeId = entry.getEquipTypeID() != null ? entry.getEquipTypeID() : 0L;

            if (firstEquipId == 0 || secondEquipId == 0 || firstEquipTypeId == 0 || secondEquipTypeId == 0) {
               // System.out.println(firstEquipId + "-- " + secondEquipId + "-- " + firstEquipTypeId + "-- " + secondEquipTypeId);
                return 0.0;
            }

            // 查找最大换型时间
            return findMaxChangeOverTime(matchingParams, secondParams, firstEquipId, secondEquipId, firstEquipTypeId, secondEquipTypeId);
        });

        // 定期清理缓存
        synchronized (this) {
            callCount++;
            if (callCount >= CLEANUP_INTERVAL) {
                cleanCachesIfNeeded();
                callCount = 0;
            }
        }

        return result;
    }

    /**
     * 获取矩阵数据（带缓存）
     */
    private List<DiscreteParameterMatrix> getMatrixDataWithCache(Set<String> groupIds) {
        if (groupIds == null || groupIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 生成缓存键
        String cacheKey = groupIds.stream()
                .filter(Objects::nonNull)
                .sorted()
                .collect(Collectors.joining(","));

        if (cacheKey.isEmpty()) {
            return Collections.emptyList();
        }

        // 使用computeIfAbsent缓存矩阵数据
        return matrixDataCache.computeIfAbsent(cacheKey, key ->
                this.lambdaQuery()
                        .in(DiscreteParameterMatrix::getGroupid, groupIds)
                        .eq(DiscreteParameterMatrix::getIsdeleted, 0)
                        .list()
        );
    }

    /**
     * 清理缓存（如果需要）
     */
    private void cleanCachesIfNeeded() {
        // 清理结果缓存
        if (resultCache.size() > MAX_RESULT_CACHE_SIZE) {
            cleanCache(resultCache, MAX_RESULT_CACHE_SIZE);
        }

        // 清理矩阵缓存
        if (matrixDataCache.size() > MAX_MATRIX_CACHE_SIZE) {
            cleanCache(matrixDataCache, MAX_MATRIX_CACHE_SIZE);
        }
    }

    /**
     * 通用的缓存清理方法
     */
    private <K, V> void cleanCache(ConcurrentHashMap<K, V> cache, int maxSize) {
        if (cache.size() <= maxSize) {
            return;
        }

        int targetSize = maxSize * 3 / 4;  // 清理到75%
        Iterator<K> iterator = cache.keySet().iterator();
        int removed = 0;

        while (cache.size() > targetSize && iterator.hasNext()) {
            iterator.next();
            iterator.remove();
            removed++;
        }
    }

    /**
     * 生成结果缓存键
     */
    private String generateCacheKey(Entry entry, Entry lastEntry,
                                    List<RoutingDiscreteParam> firstParams,
                                    List<RoutingDiscreteParam> secondParams) {
        StringBuilder key = new StringBuilder();
        key.append("E").append(entry.getId())
                .append("_LE").append(lastEntry.getId())
                .append("_EID").append(entry.getSelectMachineID())
                .append("_LEID").append(lastEntry.getSelectMachineID())
                .append("_ET").append(entry.getEquipTypeID())
                .append("_LET").append(lastEntry.getEquipTypeID());

        // 参数哈希（避免顺序影响）
        if (firstParams != null && secondParams != null) {
            key.append("_PH").append(getParamsHash(firstParams)).append("_").append(getParamsHash(secondParams));
        }
        return key.toString();
    }

    /**
     * 计算参数哈希值
     */
    private int getParamsHash(List<RoutingDiscreteParam> params) {
        if (params == null || params.isEmpty()) {
            return 0;
        }

        String paramStr = params.stream()
                .filter(Objects::nonNull)
                .map(p -> (p.getGroupId() != null ? p.getGroupId() : "") + ":" + (p.getParameterId() != null ? p.getParameterId() : ""))
                .sorted()
                .collect(Collectors.joining("#"));

        return paramStr.hashCode();
    }

    /**
     * 查找匹配的参数（first中groupId在second中存在的参数）
     */
    private List<RoutingDiscreteParam> findMatchingParams(List<RoutingDiscreteParam> firstParams, List<RoutingDiscreteParam> secondParams) {
        Set<String> secondGroupIds = secondParams.stream()
                .map(RoutingDiscreteParam::getGroupId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        return firstParams.stream()
                .filter(param -> param.getGroupId() != null && secondGroupIds.contains(param.getGroupId()))
                .collect(Collectors.toList());
    }

    /**
     * 查找最大换型时间
     */
    private double findMaxChangeOverTime(List<RoutingDiscreteParam> matchingParams,
                                         List<RoutingDiscreteParam> secondParams,
                                         long firstEquipId, long secondEquipId,
                                         long firstEquipTypeId, long secondEquipTypeId) {

        Set<String> groupIds = matchingParams.stream()
                .map(RoutingDiscreteParam::getGroupId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (groupIds.isEmpty()) {
            return 0.0;
        }

        // 获取矩阵数据（走缓存）
        List<DiscreteParameterMatrix> matrixData = getMatrixDataWithCache(groupIds);

        // 按优先级匹配矩阵记录
        List<DiscreteParameterMatrix> matchedMatrix = findMatchedMatrixByPriority(
                matchingParams, secondParams, matrixData,
                firstEquipId, secondEquipId, firstEquipTypeId, secondEquipTypeId);

        // 获取最大时长
        return getMaxDuration(matchedMatrix);
    }

    /**
     * 按优先级匹配矩阵记录（设备级→设备类型级→全局级）
     */
    private List<DiscreteParameterMatrix> findMatchedMatrixByPriority(
            List<RoutingDiscreteParam> matchingParams,
            List<RoutingDiscreteParam> secondParams,
            List<DiscreteParameterMatrix> matrixData,
            long firstEquipId, long secondEquipId,
            long firstEquipTypeId, long secondEquipTypeId) {

        // 优先级1：设备级别
        List<DiscreteParameterMatrix> result = findMatrixMatches(
                matchingParams, secondParams, matrixData, 1, 0, 0,
                firstEquipId, secondEquipId, firstEquipTypeId, secondEquipTypeId);

        if (!result.isEmpty()) {
            return result;
        }

        // 优先级2：设备类型级别
        result = findMatrixMatches(matchingParams, secondParams, matrixData, 0, 1, 0,
                firstEquipId, secondEquipId, firstEquipTypeId, secondEquipTypeId);

        if (!result.isEmpty()) {
            return result;
        }

        // 优先级3：全局级别
        return findMatrixMatches(matchingParams, secondParams, matrixData, 0, 0, 1,
                firstEquipId, secondEquipId, firstEquipTypeId, secondEquipTypeId);
    }

    /**
     * 匹配矩阵记录
     */
    private List<DiscreteParameterMatrix> findMatrixMatches(
            List<RoutingDiscreteParam> matchingParams,
            List<RoutingDiscreteParam> secondParams,
            List<DiscreteParameterMatrix> matrixData,
            int isEquip, int isEquipType, int isGlobal,
            long firstEquipId, long secondEquipId,
            long firstEquipTypeId, long secondEquipTypeId) {

        return matchingParams.stream()
                .flatMap(firstParam -> secondParams.stream()
                        .flatMap(secondParam -> matrixData.stream()
                                .filter(matrix -> isMatrixMatch(matrix, firstParam, secondParam,
                                        isEquip, isEquipType, isGlobal,
                                        firstEquipId, secondEquipId, firstEquipTypeId, secondEquipTypeId))
                        )
                )
                .collect(Collectors.toList());
    }

    /**
     * 检查矩阵是否匹配
     */
    private boolean isMatrixMatch(DiscreteParameterMatrix matrix,
                                  RoutingDiscreteParam firstParam,
                                  RoutingDiscreteParam secondParam,
                                  int requiredEquip, int requiredEquipType, int requiredGlobal,
                                  long firstEquipId, long secondEquipId,
                                  long firstEquipTypeId, long secondEquipTypeId) {

        // 参数ID匹配校验
        if (!Objects.equals(matrix.getFirstparameterid(), firstParam.getParameterId()) ||
                !Objects.equals(matrix.getSecondparameterid(), secondParam.getParameterId())) {
            return false;
        }

        // 设备级别匹配
        if (requiredEquip == 1) {
            return (matrix.getIsequip() != null ? matrix.getIsequip() : 0) == 1 &&
                    Objects.equals(matrix.getEquipid(), firstEquipId) &&
                    Objects.equals(matrix.getEquipid(), secondEquipId) &&
                    firstEquipId == secondEquipId;
        }

        // 设备类型级别匹配
        if (requiredEquipType == 1) {
            return (matrix.getIsequiptype() != null ? matrix.getIsequiptype() : 0) == 1 &&
                    Objects.equals(matrix.getEquiptypeid(), firstEquipTypeId) &&
                    Objects.equals(matrix.getEquiptypeid(), secondEquipTypeId) &&
                    firstEquipTypeId == secondEquipTypeId;
        }

        // 全局级别匹配
        if (requiredGlobal == 1) {
            return (matrix.getIsglobal() != null ? matrix.getIsglobal() : 0) == 1;
        }

        return false;
    }

    /**
     * 获取最大换型时长
     */
    private double getMaxDuration(List<DiscreteParameterMatrix> matrixList) {
        return matrixList.stream()
                .filter(matrix -> matrix.getDurationsecond() > 0)
                .map(DiscreteParameterMatrix::getDurationsecond)
                .max(Double::compareTo)
                .orElse(0.0);
    }

    /**
     * 清理所有缓存
     */
    public void clearCache() {
        resultCache.clear();
        matrixDataCache.clear();
    }
}