package com.aps.parser;

import com.aps.model.ChromosomeData;
import com.aps.model.MachineOption;
import com.aps.model.Operation;
import com.aps.model.OperationInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Chromosome排产方案解析器
 */
@Component
public class ChromosomeParser {
    
    private ChromosomeData rawData;
    private String filePath;
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 从文件加载数据
     */
    public ChromosomeData loadFromFile(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new IOException("文件不存在: " + filePath);
        }
        
        this.rawData = objectMapper.readValue(file, ChromosomeData.class);
        this.filePath = filePath;
        return this.rawData;
    }
    
    /**
     * 获取原始数据
     */
    public ChromosomeData getRawData() {
        return rawData;
    }
    
    /**
     * 从JSON字符串加载数据
     */
    public ChromosomeData loadFromJson(String jsonContent) throws IOException {
        this.rawData = objectMapper.readValue(jsonContent, ChromosomeData.class);
        return this.rawData;
    }
    
    /**
     * 获取基本信息
     */
    public Map<String, Object> getBasicInfo() {
        if (rawData == null) {
            throw new IllegalStateException("未加载数据");
        }
        
        Map<String, Object> info = new HashMap<>();
        info.put("generateType", rawData.getGenerateType());
        info.put("version", rawData.getVersion());
        info.put("operationCount", rawData.getGlobalOpList() != null ? rawData.getGlobalOpList().size() : 0);
        info.put("machineSelectionLength", rawData.getMachineSelection() != null ? rawData.getMachineSelection().size() : 0);
        info.put("operationSequenceLength", rawData.getOperationSequencing() != null ? rawData.getOperationSequencing().size() : 0);
        
        return info;
    }
    
    /**
     * 获取全局工序列表
     */
    public List<Operation> getGlobalOperations() {
        if (rawData == null || rawData.getGlobalOpList() == null) {
            return Collections.emptyList();
        }
        
        return rawData.getGlobalOpList().stream()
                .map(OperationInfo::getOp)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取机器使用统计
     */
    public Map<Integer, MachineStats> getMachineUsageStats() {
        if (rawData == null) {
            throw new IllegalStateException("未加载数据");
        }
        
        List<Integer> machineSelection = rawData.getMachineSelection();
        List<Operation> operations = getGlobalOperations();
        
        Map<Integer, MachineStats> stats = new HashMap<>();
        
        for (int i = 0; i < machineSelection.size() && i < operations.size(); i++) {
            Integer selectionValue = machineSelection.get(i);
            Operation op = operations.get(i);
            
            if (op.getMachineOptions() != null && !op.getMachineOptions().isEmpty()) {
                // machineSelection的值从1开始，需要转换为0-based索引
                if (selectionValue >= 1 && selectionValue <= op.getMachineOptions().size()) {
                    int actualIndex = selectionValue - 1;
                    Integer machineId = op.getMachineOptions().get(actualIndex).getMachineId();
                    
                    if (machineId != null) {
                        stats.computeIfAbsent(machineId, k -> new MachineStats())
                             .addOperation(op.getId());
                    }
                }
            }
        }
        
        return stats;
    }
    
    /**
     * 计算关键指标
     */
    public Map<String, Object> calculateMetrics() {
        List<Operation> operations = getGlobalOperations();
        Map<Integer, MachineStats> machineStats = getMachineUsageStats();
        
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("totalOperations", operations.size());
        metrics.put("uniqueOrders", getUniqueOrders().size());
        metrics.put("uniqueMachines", getUniqueMachines().size());
        metrics.put("totalMachinesUsed", machineStats.size());
        
        // 计算机器负载统计
        List<Integer> machineLoads = machineStats.values().stream()
                .map(MachineStats::getCount)
                .collect(Collectors.toList());
        
        if (!machineLoads.isEmpty()) {
            double avgLoad = machineLoads.stream().mapToInt(Integer::intValue).average().orElse(0.0);
            int maxLoad = Collections.max(machineLoads);
            int minLoad = Collections.min(machineLoads);
            
            // 计算标准差
            double variance = machineLoads.stream()
                    .mapToDouble(load -> Math.pow(load - avgLoad, 2))
                    .average()
                    .orElse(0.0);
            double stdDev = Math.sqrt(variance);
            
            // 负载均衡率
            double balanceRatio = maxLoad > 0 ? (double) minLoad / maxLoad : 1.0;
            
            metrics.put("avgMachineLoad", avgLoad);
            metrics.put("machineLoadStd", stdDev);
            metrics.put("maxMachineLoad", maxLoad);
            metrics.put("minMachineLoad", minLoad);
            metrics.put("loadBalanceRatio", balanceRatio);
        }
        
        return metrics;
    }
    
    /**
     * 获取唯一订单集合
     */
    public Set<String> getUniqueOrders() {
        return getGlobalOperations().stream()
                .map(Operation::getOrderId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
    }
    
    /**
     * 获取唯一机器集合
     */
    public Set<Integer> getUniqueMachines() {
        return getGlobalOperations().stream()
                .flatMap(op -> op.getMachineOptions() != null ? op.getMachineOptions().stream() : Stream.empty())
                .map(MachineOption::getMachineId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
    }
    
    /**
     * 生成数据摘要文本
     */
    public String generateSummary() {
        Map<String, Object> basicInfo = getBasicInfo();
        Map<String, Object> metrics = calculateMetrics();
        List<Integer> machineSelection = rawData.getMachineSelection();
        List<Integer> operationSequence = rawData.getOperationSequencing();
        
        StringBuilder sb = new StringBuilder();
        sb.append("================================================================================\n");
        sb.append("APS排产方案基本信息 (Chromosome格式)\n");
        sb.append("================================================================================\n");
        sb.append(String.format("生成类型: %s\n", basicInfo.get("generateType")));
        sb.append(String.format("版本号: %s\n", basicInfo.get("version")));
        sb.append(String.format("工序总数: %s\n", basicInfo.get("operationCount")));
        sb.append(String.format("机器分配方案长度: %s\n", basicInfo.get("machineSelectionLength")));
        sb.append(String.format("工序排序方案长度: %s\n", basicInfo.get("operationSequenceLength")));
        sb.append("\n");
        
        sb.append("================================================================================\n");
        sb.append("关键指标\n");
        sb.append("================================================================================\n");
        sb.append(String.format("唯一订单数: %s\n", metrics.get("uniqueOrders")));
        sb.append(String.format("唯一机器数: %s\n", metrics.get("uniqueMachines")));
        sb.append(String.format("实际使用机器数: %s\n", metrics.get("totalMachinesUsed")));
        
        if (metrics.containsKey("machineLoadStd")) {
            sb.append(String.format("平均机器负载: %.2f 工序/机器\n", metrics.get("avgMachineLoad")));
            sb.append(String.format("机器负载标准差: %.2f\n", metrics.get("machineLoadStd")));
            sb.append(String.format("最大负载: %s 工序\n", metrics.get("maxMachineLoad")));
            sb.append(String.format("最小负载: %s 工序\n", metrics.get("minMachineLoad")));
            sb.append(String.format("负载均衡率: %.2f%%\n", (Double) metrics.get("loadBalanceRatio") * 100));
        }
        
        // 添加机器分配统计
        Map<Integer, MachineStats> machineStats = getMachineUsageStats();
        if (!machineStats.isEmpty()) {
            sb.append("\n");
            sb.append("================================================================================\n");
            sb.append("机器分配统计\n");
            sb.append("================================================================================\n");
            sb.append(String.format("已分配工序的机器数: %d\n", machineStats.size()));
            
            sb.append("\n机器使用情况 (前10台):\n");
            machineStats.entrySet().stream()
                    .sorted((Map.Entry<Integer, MachineStats> e1, Map.Entry<Integer, MachineStats> e2) -> 
                            e2.getValue().getCount() - e1.getValue().getCount())
                    .limit(10)
                    .forEach(entry -> {
                        sb.append(String.format("  - 机器ID %d: %d个工序\n", entry.getKey(), entry.getValue().getCount()));
                    });
        }
        
        // 添加双层编码说明
        sb.append("\n");
        sb.append("================================================================================\n");
        sb.append("双层编码结构说明\n");
        sb.append("================================================================================\n");
        sb.append("1. 机器分配方案 (machineSelection): 每个位置表示对应工序选择第几个可选机器\n");
        sb.append("   - 例如: [1, 2, 1, ...] 表示工序0选择第1个可选机器,工序1选择第2个可选机器...\n");
        sb.append("   - 值从1开始计数,需要转换为0-based索引访问machineOptions\n");
        sb.append("\n");
        sb.append("2. 工序排序方案 (operationSequencing): 表示工序的加工优先级顺序\n");
        
        if (operationSequence != null && !operationSequence.isEmpty()) {
            String firstFive = operationSequence.subList(0, Math.min(5, operationSequence.size())).stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(", "));
            sb.append(String.format("   - 例如: [%s, ...]\n", firstFive));
            
            if (operationSequence.size() >= 3) {
                sb.append(String.format("   - 表示优先加工工序%d, 其次工序%d, 然后工序%d, ...\n",
                        operationSequence.get(0), operationSequence.get(1), operationSequence.get(2)));
            }
        }
        
        // 添加前10个工序样例
        List<Operation> operations = getGlobalOperations();
        if (!operations.isEmpty()) {
            sb.append("\n");
            sb.append("================================================================================\n");
            sb.append("工序样例 (前10个,含机器分配)\n");
            sb.append("================================================================================\n");
            
            int limit = Math.min(10, operations.size());
            for (int i = 0; i < limit; i++) {
                Operation op = operations.get(i);
                
                String assignedMachine = "未分配";
                if (i < machineSelection.size()) {
                    Integer selectionValue = machineSelection.get(i);
                    if (op.getMachineOptions() != null && !op.getMachineOptions().isEmpty()
                            && selectionValue >= 1 && selectionValue <= op.getMachineOptions().size()) {
                        int actualIndex = selectionValue - 1;
                        MachineOption option = op.getMachineOptions().get(actualIndex);
                        assignedMachine = option.getEquipName() != null ? 
                                option.getEquipName() : "机器ID:" + option.getMachineId();
                    }
                }
                
                sb.append(String.format("%d. 工序ID: %d, 订单: %s, 产品: %s, 数量: %d, 分配机器: %s\n",
                        i + 1,
                        op.getId() != null ? op.getId() : 0,
                        op.getOrderCode() != null ? op.getOrderCode() : "N/A",
                        op.getProductName() != null ? op.getProductName() : "N/A",
                        op.getQuantity() != null ? op.getQuantity() : 0,
                        assignedMachine));
            }
        }
        
        return sb.toString();
    }
    
    /**
     * 机器统计数据内部类
     */
    public static class MachineStats {
        private int count = 0;
        private List<Integer> operations = new ArrayList<>();
        
        public void addOperation(Integer opId) {
            count++;
            operations.add(opId);
        }
        
        public int getCount() {
            return count;
        }
        
        public List<Integer> getOperations() {
            return operations;
        }
    }
}
