package com.aps.entity.basic;

import lombok.Data;

import java.util.*;

/**
 * 作者：佟礼
 * 时间：2025-11-21
 */
@Data
public class GlobalParam {
    /// <summary>
    /// 是否可以打破优先级
    /// </summary>
    private  boolean IsBreakPriority  = false;
    /// <summary>
    /// 是否多台设备
    /// </summary>
    private  boolean IsMultipleMachine  = false;

    /// <summary>
    /// 是否启动设备日历
    /// </summary>
    private  boolean IsUseCalendar = true;

    /// <summary>
    /// 是否启动原材料约束
    /// </summary>
    private  boolean IsCheckMp = true;

    /// <summary>
    /// 是否启动半成品约束
    /// </summary>
    private  boolean IsCheckSf = true;

    /// <summary>
    /// 是否重叠
    /// </summary>
    private  boolean IsOverlap  = false;

    /// <summary>
    /// 是否全局倒排
    /// </summary>
    private  boolean isJit  = false;

    private boolean isOptimizer = true;

    private  boolean _smoothSetup = false; // 设置时间平滑 工序的前处理是否提前

    private  boolean _smoothChangeOver = true; // 默认true，设置时间  是否考虑换型时间

    private  boolean _smoothChangeOverInWeek = true; // 默认true，后台任务设置 休息时间是否换型

    /**
     * NSGA-II模式：true=纯帕累托（无视权重），false=加权帕累托
     */
    private boolean pureNSGAIIMode = true;

    /**
     * 半成品JIT缓冲时间（分钟）
     */
    private int semiJitBufferMinutes = 0;

    /**
     * 物料/设备固定点求解最大迭代次数
     */
    private int materialSolveMaxIterations = 8;



    /// <summary>
    /// 目标值配置列表：包含目标值的名称、是否启用、层级和权重
    /// </summary>
    private List<ObjectiveConfig> objectiveConfigs = new ArrayList<>();

    /// <summary>
    /// 目标值名称常量
    /// </summary>
    public static final String OBJECTIVE_MAKESPAN = "makespan"; // 最早完工时间
    public static final String OBJECTIVE_FLOW_TIME = "flowTime"; // 总流程时间
    public static final String OBJECTIVE_SETUP_TIME = "setupTime"; // 总换型时间
    public static final String OBJECTIVE_MACHINE_LOAD = "machineLoad"; // 机器负载均衡
    public static final String OBJECTIVE_TARDINESS = "tardiness"; // 延迟时间

    /// <summary>
    /// 构造函数，初始化默认值
    /// </summary>
    public GlobalParam() {
        // 初始化默认目标值配置
        //完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
        objectiveConfigs.add(createMinimizeObjectiveConfig(OBJECTIVE_MAKESPAN, 1, 0.4));
        objectiveConfigs.add(createMinimizeObjectiveConfig(OBJECTIVE_FLOW_TIME, 2, 0.6));
        objectiveConfigs.add(createMinimizeObjectiveConfig(OBJECTIVE_SETUP_TIME, 2, 0.39));
        objectiveConfigs.add(createMinimizeObjectiveConfig(OBJECTIVE_MACHINE_LOAD, 1, 0.3));
        objectiveConfigs.add(createMinimizeObjectiveConfig(OBJECTIVE_TARDINESS, 1, 0.3));

        objectiveConfigs.sort(Comparator.comparing((ObjectiveConfig op) -> op.getLevel()));
    }

    private ObjectiveConfig createMinimizeObjectiveConfig(String name, int level, double weight) {
        ObjectiveConfig config = new ObjectiveConfig(name, true, level, weight);
        config.setMinimize(true);
        return config;
    }

    /// <summary>
    /// 获取目标值启用状态
    /// </summary>
    public Map<String, Boolean> getObjectiveEnabled() {
        Map<String, Boolean> enabledMap = new HashMap<>();
        for (ObjectiveConfig config : objectiveConfigs) {
            enabledMap.put(config.getName(), config.isEnabled());
        }
        return enabledMap;
    }

    /// <summary>
    /// 获取目标值层级
    /// </summary>
    public Map<String, Integer> getObjectiveLevels() {
        Map<String, Integer> levelsMap = new HashMap<>();
        for (ObjectiveConfig config : objectiveConfigs) {
            levelsMap.put(config.getName(), config.getLevel());
        }
        return levelsMap;
    }

    /// <summary>
    /// 获取目标值顺序
    /// </summary>
    public List<String> getObjectiveOrder() {
        List<String> orderList = new ArrayList<>();
        for (ObjectiveConfig config : objectiveConfigs) {
            orderList.add(config.getName());
        }
        return orderList;
    }

    /// <summary>
    /// 获取目标值权重
    /// </summary>
    public Map<String, Double> getObjectiveWeights() {
        Map<String, Double> weightsMap = new HashMap<>();
        for (ObjectiveConfig config : objectiveConfigs) {
            if(config.isEnabled()) {
                weightsMap.put(config.getName(), config.getWeight());
            }
        }
        return weightsMap;
    }

    /// <summary>
    /// 根据名称获取目标值配置
    /// </summary>
    public ObjectiveConfig getObjectiveConfig(String name) {
        for (ObjectiveConfig config : objectiveConfigs) {
            if (config.getName().equals(name)) {
                return config;
            }
        }
        return null;
    }

    /// <summary>
    /// 添加目标值配置
    /// </summary>
    public void addObjectiveConfig(ObjectiveConfig config) {
        objectiveConfigs.add(config);
        objectiveConfigs.sort(Comparator.comparing((ObjectiveConfig op) -> op.getLevel()));

    }

    /// <summary>
    /// 更新目标值配置
    /// </summary>
    public void updateObjectiveConfig(String name, ObjectiveConfig config) {
        for (int i = 0; i < objectiveConfigs.size(); i++) {
            if (objectiveConfigs.get(i).getName().equals(name)) {
                objectiveConfigs.set(i, config);
                return;
            }
        }
        objectiveConfigs.sort(Comparator.comparing((ObjectiveConfig op) -> op.getLevel()));

    }

    /// <summary>
    /// 移除目标值配置
    /// </summary>
    public void removeObjectiveConfig(String name) {
        objectiveConfigs.removeIf(config -> config.getName().equals(name));
    }

    public void applyKpiConfig(Object rawConfig) {
        List<?> kpiList = extractKpiList(rawConfig);
        if (kpiList.isEmpty()) {
            return;
        }

        List<ObjectiveConfig> configs = new ArrayList<>();
        int sequence = 1;
        for (Object item : kpiList) {
            ObjectiveConfig config = toObjectiveConfig(item, sequence++);
            if (config != null) {
                configs.add(config);
            }
        }

        if (!configs.isEmpty()) {
            configs.sort(Comparator.comparing((ObjectiveConfig op) -> op.getLevel()));
            objectiveConfigs = configs;
        }
    }

    public GlobalParam copy() {
        GlobalParam target = new GlobalParam();
        target.IsBreakPriority = this.IsBreakPriority;
        target.IsMultipleMachine = this.IsMultipleMachine;
        target.IsUseCalendar = this.IsUseCalendar;
        target.IsCheckMp = this.IsCheckMp;
        target.IsCheckSf = this.IsCheckSf;
        target.IsOverlap = this.IsOverlap;
        target.isJit = this.isJit;
        target.isOptimizer = this.isOptimizer;
        target._smoothSetup = this._smoothSetup;
        target._smoothChangeOver = this._smoothChangeOver;
        target._smoothChangeOverInWeek = this._smoothChangeOverInWeek;
        target.pureNSGAIIMode = this.pureNSGAIIMode;
        target.semiJitBufferMinutes = this.semiJitBufferMinutes;
        target.materialSolveMaxIterations = this.materialSolveMaxIterations;
        target.objectiveConfigs = copyObjectiveConfigs(this.objectiveConfigs);
        return target;
    }

    public boolean isOptimizer() {
        return isOptimizer;
    }

    public boolean getIsOptimizer() {
        return isOptimizer;
    }

    public void setOptimizer(boolean optimizer) {
        isOptimizer = optimizer;
    }

    public void setIsOptimizer(boolean optimizer) {
        isOptimizer = optimizer;
    }

    private List<?> extractKpiList(Object rawConfig) {
        if (rawConfig instanceof List) {
            return (List<?>) rawConfig;
        }
        if (rawConfig instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) rawConfig;
            Object kpiConfig = map.get("kpiConfig");
            if (kpiConfig instanceof List) {
                return (List<?>) kpiConfig;
            }
            Object kpiList = map.get("kpiList");
            if (kpiList instanceof List) {
                return (List<?>) kpiList;
            }
        }
        return Collections.emptyList();
    }

    private ObjectiveConfig toObjectiveConfig(Object raw, int sequence) {
        if (raw instanceof ObjectiveConfig) {
            ObjectiveConfig source = (ObjectiveConfig) raw;
            ObjectiveConfig copy = copyObjectiveConfig(source);
            copy.setName(normalizeObjectiveName(copy.getName()));
            return isKnownObjective(copy.getName()) ? copy : null;
        }
        if (!(raw instanceof Map)) {
            return null;
        }

        Map<?, ?> map = (Map<?, ?>) raw;
        String name = normalizeObjectiveName(asString(firstValue(map, "name", "code", "fieldName")));
        if (!isKnownObjective(name)) {
            return null;
        }

        ObjectiveConfig fallback = getObjectiveConfig(name);
        ObjectiveConfig config = fallback == null ? createMinimizeObjectiveConfig(name, sequence, 1D) : copyObjectiveConfig(fallback);
        config.setName(name);
        config.setEnabled(asBoolean(firstValue(map, "enabled", "value"), config.isEnabled()));
        config.setMinimize(asBoolean(firstValue(map, "isMinimize", "minimize"), config.isMinimize()));
        config.setLevel(asInt(firstValue(map, "level", "sort"), config.getLevel()));
        config.setWeight(asDouble(firstValue(map, "weight"), config.getWeight()));
        config.setVal(asDouble(firstValue(map, "val", "valueNumber"), config.getVal()));
        return config;
    }

    private List<ObjectiveConfig> copyObjectiveConfigs(List<ObjectiveConfig> source) {
        if (source == null) {
            return new ArrayList<>();
        }
        List<ObjectiveConfig> copy = new ArrayList<>();
        for (ObjectiveConfig config : source) {
            ObjectiveConfig copied = copyObjectiveConfig(config);
            if (isKnownObjective(copied.getName())) {
                copy.add(copied);
            }
        }
        return copy;
    }

    private ObjectiveConfig copyObjectiveConfig(ObjectiveConfig source) {
        ObjectiveConfig copy = new ObjectiveConfig();
        if (source != null) {
            copy.setName(source.getName());
            copy.setEnabled(source.isEnabled());
            copy.setMinimize(source.isMinimize());
            copy.setLevel(source.getLevel());
            copy.setWeight(source.getWeight());
            copy.setVal(source.getVal());
        }
        return copy;
    }

    private Object firstValue(Map<?, ?> map, String... keys) {
        for (String key : keys) {
            if (map.containsKey(key)) {
                return map.get(key);
            }
        }
        return null;
    }

    private String normalizeObjectiveName(String name) {
        if (name == null) {
            return null;
        }
        String normalized = name.trim().replace("_", "").replace("-", "").replace(" ", "").toLowerCase(Locale.ROOT);
        switch (normalized) {
            case "makespan":
                return OBJECTIVE_MAKESPAN;
            case "flowtime":
            case "totalflowtime":
                return OBJECTIVE_FLOW_TIME;
            case "setuptime":
            case "totalsetuptime":
            case "changeovertime":
                return OBJECTIVE_SETUP_TIME;
            case "machineload":
            case "machineloadbalance":
            case "loadbalance":
                return OBJECTIVE_MACHINE_LOAD;
            case "tardiness":
            case "delaytime":
                return OBJECTIVE_TARDINESS;
            default:
                return name.trim();
        }
    }

    private boolean isKnownObjective(String name) {
        return OBJECTIVE_MAKESPAN.equals(name)
                || OBJECTIVE_FLOW_TIME.equals(name)
                || OBJECTIVE_SETUP_TIME.equals(name)
                || OBJECTIVE_MACHINE_LOAD.equals(name)
                || OBJECTIVE_TARDINESS.equals(name);
    }

    private String asString(Object value) {
        return value == null ? null : String.valueOf(value);
    }

    private boolean asBoolean(Object value, boolean defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue() != 0;
        }
        String text = String.valueOf(value).trim();
        if ("1".equals(text)) {
            return true;
        }
        if ("0".equals(text)) {
            return false;
        }
        return text.isEmpty() ? defaultValue : Boolean.parseBoolean(text);
    }

    private int asInt(Object value, int defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(String.valueOf(value).trim());
        } catch (Exception e) {
            return defaultValue;
        }
    }

    private double asDouble(Object value, double defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        if (value instanceof Number) {
            return ((Number) value).doubleValue();
        }
        try {
            return Double.parseDouble(String.valueOf(value).trim());
        } catch (Exception e) {
            return defaultValue;
        }
    }
}
