package com.infoepoch.pms.dispatchassistant.controller.langchain;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.infoepoch.pms.dispatchassistant.common.component.RedisTool;
import com.infoepoch.pms.dispatchassistant.common.component.Result;
import com.infoepoch.pms.dispatchassistant.common.exception.NotLoginException;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.common.utils.DateTool;
import com.infoepoch.pms.dispatchassistant.common.utils.JsonUtils;
import com.infoepoch.pms.dispatchassistant.controller.basic.Auth;
import com.infoepoch.pms.dispatchassistant.controller.system.DictTypeConstants;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.User;
import com.infoepoch.pms.dispatchassistant.domain.langchain.ChatMessage;
import com.infoepoch.pms.dispatchassistant.domain.langchain.chat.ChatResponse;
import com.infoepoch.pms.dispatchassistant.domain.langchain.chat.ChatService;
import com.infoepoch.pms.dispatchassistant.domain.langchain.chat.chat.ChatRequest;
import com.infoepoch.pms.dispatchassistant.domain.langchain.chat.chat.ChatSuccessResponse;
import com.infoepoch.pms.dispatchassistant.domain.langchain.chat.knowledgeBaseChat.KnowledgeBaseChatRequest;
import com.infoepoch.pms.dispatchassistant.domain.langchain.chat.knowledgeBaseChat.KnowledgeBaseChatResponse;
import com.infoepoch.pms.dispatchassistant.domain.langchain.qwen.QwenLine;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.Conversation;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.ConversationCriteria;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.ConversationService;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.line.ConversationLine;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.line.ConversationLineCriteria;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.line.ConversationLineService;
import com.infoepoch.pms.dispatchassistant.domain.langchain.record.conversation.line.QuestionRequest;
import com.infoepoch.pms.dispatchassistant.domain.system.dict.DictDataService;
import com.infoepoch.pms.dispatchassistant.domain.system.dict.SystemDictData;
import io.micrometer.core.instrument.util.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.PreDestroy;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/api/langchain")
public class LangChainController {

    @Autowired
    private Auth auth;

    @Autowired
    private ChatService chatService;
    @Autowired
    private ConversationService conversationService;
    @Autowired
    private ConversationLineService conversationLineService;
    @Autowired
    private DictDataService dictDataService;

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RedisTool redisTool;

    private static final Logger logger = LoggerFactory.getLogger(LangChainController.class);

    /**
     * 新增会话
     * @param conversation
     * @return
     * @throws NotLoginException
     */
    @PostMapping("/add-conversation")
    public Result addConversation(@RequestBody Conversation conversation) throws NotLoginException {
        if(StringUtils.isBlank(conversation.getType()))
            throw new ValidationException("会话类型不可为空");
        User user = auth.getUserReq();
        conversationService.save(conversation, user);
        return Result.successData(conversation);
    }

    /**
     * 通用对话请求
     *
     * @param chatMessage
     * @return
     */
    @PostMapping("/common-chat")
    public Result commonChat(@RequestBody ChatMessage chatMessage) {
        // 请求AI服务接口
        ChatResponse response = null;
        if (StringUtils.isBlank(chatMessage.getType())) {
            throw new ValidationException("对话类型不可为空");
        }
        List<String> allowTypeList = Arrays.asList("chat", "knowledge", "fast");
        if (!allowTypeList.contains(chatMessage.getType())) {
            throw new ValidationException("对话类型不合法");
        }
        if (chatMessage.getType().equals("chat")) {
            ChatRequest request = new ChatRequest(
                    chatMessage.getMessage(),
                    chatMessage.getConversationId(),
                    false,
                    "chatglm3-6b",
                    new BigDecimal("0.7"),
                    0,
                    "default"
            );
            List<ConversationLine> historyList = conversationService.queryConversationHistory(chatMessage.getConversationId(), 3);
            for (ConversationLine line : historyList) {
                request.addHistory("user", line.getQuery());
                request.addHistory("assistant", line.getAnswer());
            }
            String result = chatService.chat(request);
            ChatSuccessResponse chatSuccessResponse = JsonUtils.jsonToObject(result, ChatSuccessResponse.class);
            response = new ChatResponse(
                    "chat",
                    chatSuccessResponse.getText(),
                    null
            );
            // 存储对话记录
            conversationService.saveLine(chatMessage, request, response, result);
        } else if (chatMessage.getType().equals("knowledge")) {
            KnowledgeBaseChatRequest request = new KnowledgeBaseChatRequest(
                    chatMessage.getMessage(),
                    "jiangsu",
                    3,
                    1,
                    false,
                    "chatglm3-6b",
                    new BigDecimal("0.7"),
                    0,
                    "default"
            );
            String result = chatService.knowledgeChat(request);
            KnowledgeBaseChatResponse knowledgeBaseChatResponse = JsonUtils.jsonToObject(result, KnowledgeBaseChatResponse.class);
            response = new ChatResponse(
                    "knowledge",
                    knowledgeBaseChatResponse.getAnswer(),
                    knowledgeBaseChatResponse.getDocs()
            );
            // 存储对话记录
            conversationService.saveLine(chatMessage, request, response, result);
        }
        // 返回结果
        if (response == null) {
            return Result.error(-1, "获取对话结果失败");
        }
        return Result.successData(response);
    }


    /**
     * 通用对话请求
     *
     * @param chatMessage
     * @return
     */
    @PostMapping("/queryAnswer")
    public Result queryAnswer(@RequestBody String chatMessage) {
        // 请求AI服务接口
        String result="";
        result=conversationService.queryAnswer(chatMessage);
        return Result.successData(result);
    }



    /**
     * 会话类型列表
     *
     * @return
     */
    @GetMapping("/type-list")
    public Result typeList() {
        // 根据字典类型查询系统字典数据
        List<SystemDictData> dictDataList = dictDataService.queryByDictType(DictTypeConstants.CONVERSATION_TYPE);
        // 返回查询结果
        return Result.successData(dictDataList);
    }

    /**
     * 会话列表
     *
     * @param type
     * @return
     */
    @GetMapping("/conversation-list/{type}")
    public Result conversationList(@PathVariable String type) throws NotLoginException {
        User user = auth.getUserReq();
        ConversationCriteria criteria = new ConversationCriteria();
        criteria.setType(type);
        criteria.setUserId(user.getId());
        List<Conversation> conversationList = conversationService.list(criteria);
        return Result.successData(conversationList);
    }

    /**
     * 会话记录列表
     *
     * @param conversationId
     * @return
     */
    @GetMapping("/conversation-history/{conversationId}")
    public Result conversationHistory(@PathVariable String conversationId) {
        ConversationLineCriteria criteria = new ConversationLineCriteria();
        criteria.setConversationId(conversationId);
        List<ConversationLine> conversationHistory = conversationLineService.list(criteria);
        return Result.successData(conversationHistory);
    }

    /**
     * @param message
     * @return
     */
    @PostMapping("/chat")
    public Result chat(String message) {
        ChatRequest request = new ChatRequest(
                message,
                "1",
                false,
                "chatglm3-6b",
                new BigDecimal("0.7"),
                0,
                "default"
        );
        String result = chatService.chat(request);
        ChatSuccessResponse chatSuccessResponse = JsonUtils.jsonToObject(result, ChatSuccessResponse.class);
        ChatResponse response = new ChatResponse(
                "chat",
                chatSuccessResponse.getText(),
                null
        );
        return Result.successData(response);
    }

    /**
     * @param message
     * @return
     */
    @PostMapping("/knowledge-chat")
    public Result knowledgeChat(String message) {
        KnowledgeBaseChatRequest request = new KnowledgeBaseChatRequest(
                message,
                "jiangsu",
                3,
                1,
                false,
                "chatglm3-6b",
                new BigDecimal("0.7"),
                0,
                "default"
        );
        String result = chatService.knowledgeChat(request);
        KnowledgeBaseChatResponse knowledgeBaseChatResponse = JsonUtils.jsonToObject(result, KnowledgeBaseChatResponse.class);
        ChatResponse response = new ChatResponse(
                "knowledge",
                knowledgeBaseChatResponse.getAnswer(),
                knowledgeBaseChatResponse.getDocs()
        );
        return Result.successData(response);
    }

    //调用智能体
    @GetMapping("/sseIntelligent")
    public ResponseEntity<SseEmitter> sse(@RequestParam String  chatMessage) {
        //  curl http://10.32.41.228:39080/v1/chat/completions -X POST
        // -H "Content-Type:application/json;charset=UTF-8"
        // -H "AI-API-CODE:usOPREkI33" -H "AI-APP-KEY:vXRDti1mJg"
        // --data '{"stream":false,"model":"Qwen1.5-32B-NPU910B","messages":[{"role":"user","content":""}]} '
        String urlAddr = "http://10.32.41.35:40517/scene_gateway/agent/6809d0895428476bb6789ad70c525c97";
        BufferedReader reader = null;
        try {
            URL url = new URL(urlAddr);
            // 建立链接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            String responseEntity="";
            QuestionRequest questionRequest=new QuestionRequest();
            questionRequest.setKeyword(chatMessage);
            // (yyyyMMddHHmmssSSS)+6位随机数;
            Random random = new Random();
            Integer min = 100000; // 最小值（6位起始）
            Integer max = 999999; // 最大值（6位结束）
            // 生成范围：min <= num <= max
            Integer randomNum = random.nextInt(max - min + 1) + min;
            String currentDay = DateTool.format(new Date(), "yyyyMMddHHmmssSSS");
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Accept", "text/event-stream");
            connection.setRequestProperty("Content-type", "application/json; charset=UTF-8");
            connection.setRequestProperty("AuthToken", "4009fe23e6b648539792330c14f5ed8e");
            connection.setRequestProperty("Cache-Control", "no-cache");
            connection.setRequestProperty("Connection", "keep-alive");
            questionRequest.setRequestId(currentDay+randomNum.toString());
            questionRequest.setDialogId(currentDay+randomNum.toString());
            String params = JsonUtils.objectToJson(questionRequest);
            // 允许输入和输出
            connection.setDoInput(true);
            connection.setDoOutput(true);
            // 设置超时为0，表示无限制
            connection.setConnectTimeout(0);
            connection.setReadTimeout(0);
            // 传参
            //String params = "prompt=哈哈哈哈";
            // 写入POST数据
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            out.write(params.getBytes(StandardCharsets.UTF_8));
            out.flush();
            out.close();
            // 读取SSE事件
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
            String line;
            SseEmitter emitter = new SseEmitter();
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                emitter.send(SseEmitter.event().data(line));
            }
            reader.close();
            System.out.println(" __stop__");
            emitter.send(SseEmitter.event().data(" __stop__"));
            emitter.complete();
            // 断开链接
            connection.disconnect();
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_EVENT_STREAM_VALUE)
                    .body(emitter);
        } catch (Exception e) {
            logger.info(e.getMessage());
            e.printStackTrace();
        } finally {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_EVENT_STREAM_VALUE)
                    .body( null);
            //IoUtils.copy(reader);
        }
    }


    //模拟see接口
    @GetMapping("/simulate")
    public ResponseEntity<SseEmitter> simulateStream(@RequestParam String chatMessage,@RequestParam String sessionId) {
        // 在这里处理authToken，验证用户身份
        // ...
        //
        String history= redisTool.get(sessionId);
        List<Map<String,Object>> historyList=new ArrayList<>();
        if(StringUtils.isNotEmpty(history))
            historyList= JsonUtils.jsonToMapList(history);
        Map map=new HashMap<>();
        map.put("stream",true);
        map.put("model","qwen");
        map.put("max_tokens",2048);
        List<Map<String,Object>> mesList=new ArrayList<>();
        Map mes=new HashMap<>();
        mes.put("role","user");
        mes.put("content",chatMessage);
        mesList.add(mes);
        if(historyList!=null&&historyList.size()>0) {
            historyList.addAll(mesList);
            map.put("messages", historyList);
        }else
        {

            historyList.addAll(mesList);
            map.put("messages", historyList);
        }
        SseEmitter emitter = new SseEmitter();
        Map mapGet=new HashMap<>();
        StringBuffer contentGet =new StringBuffer();
        // 使用线程模拟发送SSE事件
        List<Map<String, Object>> finalHistoryList = historyList;
        new Thread(() -> {
            try {
                for (int i = 0; i < 2; i++) {
                    // 这里可以基于keyword, requestId, dialogId处理逻辑，但示例中仅发送简单事件
                    contentGet.append("当"+i);
                    emitter.send(SseEmitter.event().data("当"+i),MediaType.parseMediaType("application/json; charset=UTF-8"));
                    Thread.sleep(1000); // 每秒发送一个事件
                }
                emitter.send(SseEmitter.event().data("stop"),MediaType.parseMediaType("application/json; charset=UTF-8"));
                mapGet.put("role","assistant");
                mapGet.put("content",contentGet.toString());
                finalHistoryList.add(mapGet);
                redisTool.put(sessionId, JsonUtils.objectToJson(finalHistoryList), 2, TimeUnit.HOURS);
                Thread.sleep(1000);
                emitter.complete();
            } catch (Exception e) {
                emitter.completeWithError(e);
            }
        }).start();


        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_EVENT_STREAM_VALUE)
                .body(emitter);
    }


    //调用大模型接口
    @GetMapping("/sseQwen")
    public  ResponseEntity<SseEmitter> sseBigTwo(@RequestParam String  chatMessage,@RequestParam String sessionId) {

        String history= redisTool.get(sessionId);
        List<Map<String,Object>> historyList=new ArrayList<>();
        if(StringUtils.isNotEmpty(history))
            historyList= JsonUtils.jsonToMapList(history);

        // 发送请求体
        Map map=new HashMap<>();
        map.put("stream",true);
        map.put("model","qwen");
        map.put("max_tokens",2048);
        List<Map<String,Object>> messageList=new ArrayList<>();
        Map message=new HashMap<>();
        message.put("role","user");
        message.put("content",chatMessage);
        messageList.add(message);
        map.put("messages",messageList);
        if(historyList!=null&&historyList.size()>0) {
            historyList.addAll(messageList);
            map.put("messages", historyList);
        }else
        {
            historyList.addAll(messageList);
            map.put("messages", historyList);
        }

        SseEmitter emitter = new SseEmitter(0L); // 超时时间设为无限
        Map mapAssistant=new HashMap<>();
        StringBuffer contentAssistant =new StringBuffer();
        // 启动线程处理 SSE 连接
        List<Map<String, Object>> finalHistoryList = historyList;
        new Thread(() -> {
            HttpURLConnection connection = null;
            try {
                URL url = new URL("http://10.32.41.228:39080/v1/chat/completions");
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
                connection.setRequestProperty("AI-API-CODE", "7xU7Aa1IMj");
                connection.setRequestProperty("AI-APP-KEY", "vXRDti1mJg");
                connection.setDoOutput(true);

                String jsonInputString =JsonUtils.objectToJson(map);
                logger.info(jsonInputString);
                try (OutputStream os = connection.getOutputStream()) {
                    os.write(jsonInputString.getBytes(StandardCharsets.UTF_8));
                    os.flush();
                }
                // 检查响应码
                int responseCode = connection.getResponseCode();
                if (responseCode != HttpURLConnection.HTTP_OK) {
                    emitter.completeWithError(new RuntimeException("SSE 连接失败: " + responseCode));
                    return;
                }

                // 持续读取 SSE 数据流
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        if (line.startsWith("data: ")) {
                            String data = line.substring(5).trim();
                            QwenLine qwenLine= JsonUtils.jsonToObject(data,QwenLine.class);
                            String lineContent=qwenLine.getChoices().get(0).getDelta().getContent();
                            String lineFinish=qwenLine.getChoices().get(0).getFinish_reason();
                            logger.info(lineContent);
                            logger.info(lineFinish);
                            if("stop".equals(lineFinish))
                            {
                                emitter.send(SseEmitter.event().data("stop"),MediaType.parseMediaType("application/json; charset=UTF-8"));
                                mapAssistant.put("role","assistant");
                                mapAssistant.put("content",contentAssistant.toString());
                                finalHistoryList.add(mapAssistant);
                                redisTool.put(sessionId, JsonUtils.objectToJson(finalHistoryList), 2, TimeUnit.HOURS);
                            }else
                            {
                                contentAssistant.append(lineContent);
                                emitter.send(SseEmitter.event().data(lineContent),MediaType.parseMediaType("application/json; charset=UTF-8"));
                            }
                            logger.info(line);
                            logger.info(lineContent);
                            // 将数据转发给前端
                        }
                    }
                }
                emitter.complete(); // 流结束
            } catch (Exception e) {
                emitter.completeWithError(e);
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }).start();

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_EVENT_STREAM_VALUE)
                .body(emitter);
    }



    private static final CloseableHttpClient httpClient;

    private static final Logger log = LoggerFactory.getLogger(LangChainController.class);
    static {
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
        connManager.setMaxTotal(100);
        connManager.setDefaultMaxPerRoute(20);

        httpClient = HttpClients.custom()
                .setConnectionManager(connManager)
                .build();
    }

    @GetMapping("/chat-stream")
    public SseEmitter chatStream(@RequestParam("chatMessage") String chatMessage) {
        SseEmitter emitter = new SseEmitter(30 * 60 * 1000L);
        Map map=new HashMap<>();
        map.put("stream",true);
        map.put("model","qwen");
        map.put("max_tokens",2048);
        List<Map> mesList=new ArrayList<>();
        Map mes=new HashMap<>();
        mes.put("role","user");
        mes.put("content",chatMessage);
        mesList.add(mes);
        map.put("messages",mesList);
        String jsonInputString =JsonUtils.objectToJson(map);
        new Thread(() -> {
            try{
                // 使用HttpComponents更优雅的请求构建方式
                HttpPost post = new HttpPost("http://10.32.41.228:39080/v1/chat/completions");
                //post.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey);
                post.addHeader("Content-Type", "application/json;charset=UTF-8");
                post.addHeader("AI-API-CODE", "7xU7Aa1IMj");
                post.addHeader("AI-APP-KEY", "vXRDti1mJg");
                post.setEntity(new StringEntity(objectMapper.writeValueAsString(jsonInputString),
                        ContentType.APPLICATION_JSON));
                // 执行请求（带重试）
                try (CloseableHttpResponse response = httpClient.execute(post)) {
                    processStreamResponse(response, emitter);
                }
            } catch (Exception e) {
                handleException(e, emitter);
            }
        }).start();

        // 超时和完成回调
        emitter.onTimeout(() -> log.warn("SSE连接超时"));
        emitter.onCompletion(() -> log.info("SSE连接完成"));
        return emitter;
    }

    // 流式响应处理私有方法
    private void processStreamResponse(HttpResponse response, SseEmitter emitter)
            throws IOException {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(response.getEntity().getContent()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("data: ")) {
                    String data = line.substring(5).trim();
                    QwenLine qwenLine= JsonUtils.jsonToObject(data,QwenLine.class);
                    String lineContent=qwenLine.getChoices().get(0).getDelta().getContent();
                    String lineFinish=qwenLine.getChoices().get(0).getFinish_reason();
                    if ("stop".equals(lineFinish)) break;
                    logger.info(line);
                    logger.info(lineContent);
                    if (!lineContent.isEmpty()) {
                        emitter.send(SseEmitter.event()
                                .data(lineContent)
                                .id(UUID.randomUUID().toString()));
                    }
                }
            }
            emitter.complete();
        }
    }

    @PreDestroy
    public void destroy() throws IOException {
        httpClient.close(); // 程序退出时关闭
    }

    // 统一异常处理
    private void handleException(Exception e, SseEmitter emitter) {
        log.error("API调用异常", e);
        if (e instanceof SocketTimeoutException) {
            emitter.completeWithError(new RuntimeException("连接DeepSeek服务超时"));
        } else {
            emitter.completeWithError(new RuntimeException("服务内部错误"));
        }
    }

    @GetMapping("/getSessionId")
    public Result getSessionId() {
        return Result.successData(UUID.randomUUID().toString().replace("-", ""));
    }


}
