package com.aps.llm;

import com.aps.config.LLMConfig;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 大语言模型客户端
 */
@Component
public class LLMClient {
    
    @Autowired
    private LLMConfig config;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 调用聊天完成API
     */
    public String chatCompletion(List<Map<String, String>> messages) throws Exception {
        return chatCompletion(messages, null, null, null);
    }
    
    /**
     * 调用聊天完成API（带自定义参数）
     */
    public String chatCompletion(List<Map<String, String>> messages, 
                                  Double temperature, 
                                  Integer maxTokens,
                                  String model) throws Exception {
        
        CloseableHttpClient httpClient = HttpClients.createDefault();
        
        try {
            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model", model != null ? model : config.getModel());
            requestBody.put("messages", messages);
            requestBody.put("temperature", temperature != null ? temperature : config.getTemperature());
            requestBody.put("max_tokens", maxTokens != null ? maxTokens : config.getMaxTokens());
            
            String jsonBody = objectMapper.writeValueAsString(requestBody);
            
            // 创建HTTP POST请求
            HttpPost httpPost = new HttpPost(config.getBaseUrl() + "/chat/completions");
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("Authorization", "Bearer " + config.getApiKey());
            
            httpPost.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8));
            
            // 设置超时
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(30000)
                    .setSocketTimeout(60000)
                    .build();
            httpPost.setConfig(requestConfig);
            
            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                int statusCode = response.getStatusLine().getStatusCode();
                String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                
                if (statusCode != 200) {
                    throw new RuntimeException("API调用失败: HTTP " + statusCode + ", 响应: " + responseBody);
                }
                
                // 解析响应
                JsonNode rootNode = objectMapper.readTree(responseBody);
                JsonNode choicesNode = rootNode.path("choices");
                
                if (choicesNode.isArray() && choicesNode.size() > 0) {
                    return choicesNode.get(0).path("message").path("content").asText();
                } else {
                    throw new RuntimeException("API响应格式错误: " + responseBody);
                }
            }
        } finally {
            httpClient.close();
        }
    }
    
    /**
     * 诊断排产计划
     */
    public String diagnoseSchedule(String scheduleSummary, 
                                   String rulesContext,
                                   List<String> diagnosisFocus) throws Exception {
        
        StringBuilder focusText = new StringBuilder();
        if (diagnosisFocus != null && !diagnosisFocus.isEmpty()) {
            focusText.append("\n\n请重点关注以下方面:\n");
            for (String focus : diagnosisFocus) {
                focusText.append("- ").append(focus).append("\n");
            }
        }
        
        String systemPrompt = buildSystemPrompt(rulesContext, focusText.toString());
        
        List<Map<String, String>> messages = new ArrayList<>();
        messages.add(createMessage("system", systemPrompt));
        messages.add(createMessage("user", "请诊断以下排产计划:\n\n" + scheduleSummary));
        
        return chatCompletion(messages);
    }
    
    /**
     * 构建系统提示词
     */
    private String buildSystemPrompt(String rulesContext, String focusText) {
        return String.format(
            "你是一个APS（高级计划与排程）系统专家，需要用通俗易懂的语言帮助用户理解排产方案。\n\n" +
            "## 你的任务\n" +
            "基于提供的排产计划数据，进行诊断分析，用简单明了的语言指出问题、瓶颈和优化机会。\n\n" +
            "## 重要要求：使用中文术语\n" +
            "在诊断报告中，所有技术参数必须使用中文名称，禁止直接使用英文变量名！\n\n" +
            "### 术语对照表（请使用左侧中文名称）\n" +
            "machineSelection = 机器分配方案\n" +
            "operationSequencing = 工序排序方案\n" +
            "globalOpList = 工序详细信息列表\n" +
            "machineOptions = 可选机器列表\n" +
            "machineId = 机器ID\n" +
            "equipName = 设备名称\n" +
            "orderCode = 订单编码\n" +
            "productName = 产品名称\n" +
            "quantity = 生产数量\n" +
            "runtime = 运行时间\n" +
            "singleOut = 单件产出\n" +
            "Makespan = 最大完工时间\n" +
            "Load Balance = 负载均衡\n" +
            "Bottleneck = 瓶颈资源\n\n" +
            "## 输出格式要求（非常重要）\n" +
            "1. 使用简洁的段落，避免过多符号和复杂格式\n" +
            "2. 使用简单的编号（1. 2. 3.），不要用复杂的标记符号\n" +
            "3. 语言要通俗易懂，就像跟普通工人解释一样\n" +
            "4. 避免使用Markdown的复杂语法（如加粗、表格等）\n" +
            "5. 每个要点独立成段，清晰明了\n" +
            "6. 不要使用✅等特殊符号\n\n" +
            "## Chromosome数据结构说明\n" +
            "本次诊断的数据采用Chromosome双层编码格式：\n" +
            "1. 机器分配方案：每个位置表示对应工序选择第几个可选机器。例如：[1, 1, 1, ...] 表示所有工序都选择第1个可选机器\n" +
            "2. 工序排序方案：表示工序的加工优先级顺序。例如：[2534, 587, 1690, ...] 表示优先加工工序2534，其次587，然后1690\n\n" +
            "## 诊断内容要求\n" +
            "请按以下结构输出诊断结果：\n\n" +
            "一、整体评价\n" +
            "用2-3句话简单说明这个排产方案怎么样，打分（满分100分）\n\n" +
            "二、主要优点\n" +
            "列出2-3个做得好的地方\n\n" +
            "三、存在的问题\n" +
            "列出2-4个需要注意的问题，用通俗语言解释\n\n" +
            "四、优化建议\n" +
            "给出3-5条具体可行的改进建议，每条建议简单说明怎么做\n\n" +
            "五、总结\n" +
            "用1-2句话总结，告诉用户这个方案是否可以接受，是否需要优化\n\n" +
            "## 注意事项\n" +
            "1. 不要误判未分配机器：机器分配方案中所有值都是有效的机器索引\n" +
            "2. 关注负载均衡：如果所有工序都分配到同一台机器，这是严重问题\n" +
            "3. 基于数据说话：引用具体的工序数、机器数、负载统计等数据\n" +
            "4. 严格使用中文术语：所有技术参数必须使用上述对照表中的中文名称\n" +
            "5. 语言要通俗易懂，避免专业术语堆砌\n" +
            "6. 格式要简洁美观，方便阅读\n\n" +
            "请基于数据进行客观分析，给出专业但易懂的建议。\n" +
            "%s",
            rulesContext
        );
    }
    
    /**
     * 创建消息对象
     */
    private Map<String, String> createMessage(String role, String content) {
        Map<String, String> message = new HashMap<>();
        message.put("role", role);
        message.put("content", content);
        return message;
    }
    
    /**
     * 交互式对话
     */
    public String interactiveChat(List<Map<String, String>> conversationHistory, 
                                  String contextInfo) throws Exception {
        
        String systemPrompt = "你是一个APS排产诊断助手,帮助用户分析和优化排产方案。\n\n" +
                "## 你的能力\n" +
                "1. 诊断排产计划的问题和瓶颈\n" +
                "2. 提供优化建议和改进方案\n" +
                "3. 处理机器检修等突发情况\n" +
                "4. 对比不同排产方案\n" +
                "5. 回答用户关于排产的疑问\n\n" +
                "## 当前上下文\n" +
                contextInfo + "\n\n" +
                "## 对话原则\n" +
                "- 基于数据和规则进行分析\n" +
                "- 给出具体、可操作的建议\n" +
                "- 保持专业和友好的语气\n" +
                "- 如果信息不足,主动询问用户\n";
        
        List<Map<String, String>> messages = new ArrayList<>();
        messages.add(createMessage("system", systemPrompt));
        messages.addAll(conversationHistory);
        
        return chatCompletion(messages);
    }
    
    /**
     * 通用对话（无需加载数据）
     */
    public String generalChat(List<Map<String, String>> conversationHistory) throws Exception {
        
        String systemPrompt = "你是一个专业的APS(高级计划与排程)系统专家助手。\n\n" +
                "## 你的角色\n" +
                "你可以帮助用户解答关于APS排产系统的各种问题，包括：\n" +
                "1. APS系统的基本概念和原理\n" +
                "2. 生产排程的优化方法\n" +
                "3. 机器调度和资源分配策略\n" +
                "4. 工序排序的最佳实践\n" +
                "5. 负载均衡和瓶颈分析\n" +
                "6. 排产方案的评估标准\n\n" +
                "## 对话原则\n" +
                "- 用通俗易懂的语言解释专业概念\n" +
                "- 给出具体、实用的建议\n" +
                "- 保持专业和友好的语气\n" +
                "- 如果问题超出APS领域，礼貌地告知用户\n" +
                "- 鼓励用户提供更多背景信息以便给出更精准的建议\n";
        
        List<Map<String, String>> messages = new ArrayList<>();
        messages.add(createMessage("system", systemPrompt));
        messages.addAll(conversationHistory);
        
        return chatCompletion(messages);
    }
}
