package com.cy.guoyan.admin.module.ai.service.chatmessage;

import com.alibaba.fastjson.JSONObject;
import com.cy.guoyan.admin.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cy.guoyan.admin.framework.security.core.util.SecurityFrameworkUtils;
import com.cy.guoyan.admin.module.ai.controller.admin.chatmessage.vo.ChatMessagePageReqVO;
import com.cy.guoyan.admin.module.ai.controller.admin.chatmessage.vo.ChatMessageRespVO;
import com.cy.guoyan.admin.module.ai.controller.admin.chatmessage.vo.ChatMessageSaveReqVO;
import com.cy.guoyan.admin.module.ai.controller.admin.chatmessage.vo.ChatMessageSendReqVO;
import com.cy.guoyan.admin.module.ai.dal.dataobject.chatapp.ChatAppDO;
import com.cy.guoyan.admin.module.ai.dal.dataobject.chatsession.ChatSessionDO;
import com.cy.guoyan.admin.module.ai.dal.mysql.chatapp.ChatAppMapper;
import com.cy.guoyan.admin.module.ai.dal.mysql.chatknowledgedataset.ChatKnowledgeDatasetMapper;
import com.cy.guoyan.admin.module.ai.dal.mysql.chatsession.ChatSessionMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.annotation.Validated;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.cy.guoyan.admin.module.ai.dal.dataobject.chatmessage.ChatMessageDO;
import com.cy.guoyan.admin.framework.common.pojo.PageResult;
import com.cy.guoyan.admin.framework.common.util.object.BeanUtils;
import com.cy.guoyan.admin.module.ai.dal.mysql.chatmessage.ChatMessageMapper;
import static com.cy.guoyan.admin.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cy.guoyan.admin.module.system.enums.ErrorCodeConstants.*;

/**
 * AI聊天消息 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class ChatMessageServiceImpl implements ChatMessageService {

    @Resource
    private ChatKnowledgeDatasetMapper chatKnowledgeDatasetMapper;

    @Resource
    private ChatMessageMapper chatMessageMapper;

    @Resource
    private ChatSessionMapper chatSessionMapper;

    @Resource
    private ChatAppMapper chaAppMapper;

    @Value("${dify.baseUrl}")
    private String difyBaseUrl;

//    @Value("${dify.chatKey}")
//    private String difyApiKey;

    public ChatAppDO getAppKey(ChatMessageSendReqVO sendReqVO) {
        ChatAppDO appDO = new ChatAppDO();
        if (StringUtils.isBlank(sendReqVO.getName())) {
            throw exception(CHAT_APP_NOT_EXISTS);
        } else {
            if (sendReqVO.getNetworking() == true) {
                appDO = chaAppMapper.selectOne(new LambdaQueryWrapperX<ChatAppDO>().like(ChatAppDO::getAppName, sendReqVO.getName()).eq(ChatAppDO::getNetworking, 1));
            }else {
                appDO = chaAppMapper.selectOne(new LambdaQueryWrapperX<ChatAppDO>().like(ChatAppDO::getAppName, sendReqVO.getName()).eq(ChatAppDO::getNetworking, 0));
            }
            if (appDO == null) {
                throw exception(CHAT_APP_NOT_EXISTS);
            }
            return appDO;
        }
    }


    @Override
    public void sendChatMessageStream(ChatMessageSendReqVO sendReqVO, HttpServletResponse response) {
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Connection", "keep-alive");

        PrintWriter writer;
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            throw new RuntimeException("获取输出流失败", e);
        }

        // 获取登录用户信息
        String nickname = String.valueOf(SecurityFrameworkUtils.getLoginUser().getInfo().get("nickname"));

        // ====== 1. 如果未传 conversationId，则不发送（Dify 会自动生成） ======
        String conversationId = sendReqVO.getDifyConversationId();

        // ====== 2. 构造 Dify 请求体 ======
        JSONObject requestBody = new JSONObject();
        requestBody.put("query", sendReqVO.getQuery());
        requestBody.put("inputs", Optional.ofNullable(sendReqVO.getInputs()).orElse(new HashMap<>()));
        requestBody.put("user", nickname);
        requestBody.put("response_mode", "streaming");
        requestBody.put("auto_generate_name", sendReqVO.getAutoGenerateName());
        if (conversationId != null) {
            requestBody.put("conversation_id", conversationId);
        }
        ChatAppDO appDO = getAppKey(sendReqVO);
        // ====== 3. 请求 Dify Chat-API ======
        HttpURLConnection conn;
        try {

            conn = (HttpURLConnection) new URL(difyBaseUrl + "/chat-messages").openConnection();
            conn.setRequestProperty("Authorization", "Bearer " + appDO.getAppKey());
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");

            log.info("请求地址: " + difyBaseUrl + "/v1/chat-messages");
            log.info("Authorization: Bearer " + appDO.getAppKey());
            log.info("请求体: " + requestBody.toJSONString());

            try (OutputStream os = conn.getOutputStream()) {
                os.write(requestBody.toJSONString().getBytes(StandardCharsets.UTF_8));
            }
        } catch (IOException e) {
            sendSseError(writer, "请求 Dify 失败：" + e.getMessage());
            return;
        }

        // ====== 4. 读取 Dify 的 SSE 流响应并转发给前端 ======
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            StringBuilder answerBuilder = new StringBuilder();
            String messageId = null;
            String returnedConversationId = conversationId;

            while ((line = reader.readLine()) != null) {
                if (line.startsWith("data: ")) {
                    String jsonStr = line.substring(6);
                    JSONObject json = JSONObject.parseObject(jsonStr);
                    String event = json.getString("event");

                    if ("message".equals(event)) {
                        String content = json.getString("answer");
                        messageId = json.getString("id");
                        answerBuilder.append(content);

                        writer.write("data: " + jsonStr + "\n\n");
                        writer.flush();

                    } else if ("message_end".equals(event)) {
                        // 获取 Dify 返回的 conversation_id
                        returnedConversationId = json.getString("conversation_id");
                        // 保存聊天记录
                        ChatMessageDO message = new ChatMessageDO();
                        message.setDifyMessageId(messageId);
                        message.setDifyConversationId(returnedConversationId);
                        message.setUserId(nickname);
                        message.setCreateTime(LocalDateTime.now());
                        // 若之前没有本地会话，创建并记录 UUID
                        if (conversationId == null) {
                            ChatSessionDO session = new ChatSessionDO();
                            session.setName("新会话 - " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                            session.setUserId(nickname);
                            session.setAppId(appDO.getId());
                            session.setDifyConversationId(returnedConversationId); // 假设你有这个字段
                            chatSessionMapper.insert(session);
                            message.setSessionId(session.getId());
                            asyncUpdateSessionName(returnedConversationId, session.getId(),appDO.getAppKey());

                        }
                        chatMessageMapper.insert(message);
                    }
                }
            }
        } catch (IOException e) {
            try (InputStream errorStream = conn.getErrorStream()) {
                if (errorStream != null) {
                    String errorResponse = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8))
                            .lines().collect(Collectors.joining("\n"));
                    log.error("Dify 接口返回错误: {}", errorResponse);
                    sendSseError(writer, errorResponse);
                } else {
                    log.error("Dify 请求失败，且无错误流可读", e);
                    sendSseError(writer, "读取 Dify 错误响应失败：" + e.getMessage());
                }
            } catch (IOException ex) {
                log.error("读取 Dify 错误流时出错", ex);
                sendSseError(writer, "读取 Dify 错误流失败：" + ex.getMessage());
            }
        }
    }

    // ====== 工具方法：发送 SSE 错误信息 ======
    private void sendSseError(PrintWriter writer, String errorJson) {
        try {
            JSONObject response = new JSONObject();
            try {
                JSONObject parsedError = JSONObject.parseObject(errorJson);
                response.put("error", parsedError); // 嵌套 JSON
            } catch (Exception ex) {
                response.put("error", errorJson); // 普通字符串
            }

            writer.write("data: " + response.toJSONString() + "\n\n");
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void asyncUpdateSessionName(String difyConversationId, Long localSessionId,String difyApiKey) {
        CompletableFuture.runAsync(() -> {
            try {
                // 等待 Dify 生成名称（一般 1～3 秒即可）
                Thread.sleep(5000);

                // 构造 URL 请求
                HttpURLConnection conn = (HttpURLConnection) new URL(difyBaseUrl + "/v1/conversations/" + difyConversationId).openConnection();
                conn.setRequestMethod("GET");
                conn.setRequestProperty("Authorization", "Bearer " + difyApiKey);

                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {
                    try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                        String body = br.lines().collect(Collectors.joining("\n"));
                        JSONObject json = JSONObject.parseObject(body);
                        log.info("Dify 会话名称: {}", json.toJSONString());
                        String name = json.getString("name");

                        if (StringUtils.isNotBlank(name)) {
                            ChatSessionDO update = new ChatSessionDO();
                            update.setId(localSessionId);
                            update.setName(name);
                            chatSessionMapper.updateById(update); // 使用 MyBatisPlus 更新
                            log.info("成功更新 Dify 会话名称为: {}", name);
                        }
                    }
                } else {
                    log.warn("获取 Dify 会话名称失败，状态码: {}", responseCode);
                }

            } catch (Exception e) {
                log.error("异步更新 Dify 会话名称异常", e);
            }
        });
    }


    @Override
    public ChatMessageRespVO sendChatMessageBlock(ChatMessageSendReqVO sendReqVO) throws IOException {
        String conversationId = sendReqVO.getDifyConversationId();
        // 1. 从登录上下文取用户昵称
        String nickname = String.valueOf(SecurityFrameworkUtils.getLoginUser().getInfo().get("nickname"));
        ChatMessageDO msg = new ChatMessageDO();
        msg.setUserId(nickname);
        msg.setContent(sendReqVO.getQuery());
        msg.setRole("user");
        if (StringUtils.isNotBlank(conversationId)) {
            msg.setDifyConversationId(conversationId);
        }
        chatMessageMapper.insert(msg);
        ChatAppDO appDO = getAppKey(sendReqVO);

        // 2. 构造请求体
        JSONObject body = new JSONObject();
        body.put("query", sendReqVO.getQuery());
        body.put("inputs", Optional.ofNullable(sendReqVO.getInputs()).orElse(new HashMap<>()));
        if (StringUtils.isNotBlank(conversationId)) {
            body.put("conversation_id", conversationId);
        }
        body.put("user", nickname);
        body.put("response_mode", "blocking");
        body.put("auto_generate_name", true);
        body.put("enable_retrieval", true);
//        ChatKnowledgeDatasetDO datasetDO = chatKnowledgeDatasetMapper.selectById(sendReqVO.getDifyDatasetId());
//        body.put("datasets", Collections.singletonList(datasetDO.getDifyDatasetId()));
        log.info("Dify 请求体: {}", body.toJSONString());
        // 3. 发起 HTTP POST
        URL url = new URL(difyBaseUrl + "/v1/chat-messages");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty("Authorization", "Bearer " + appDO.getAppKey());
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        try (OutputStream os = conn.getOutputStream()) {
            os.write(body.toJSONString().getBytes(StandardCharsets.UTF_8));
        }

        // 5. 读取响应（
        int code = conn.getResponseCode();
        InputStream rawStream = (code >= 200 && code < 300)
                ? conn.getInputStream()
                : conn.getErrorStream();

        String respStr;
        if (rawStream == null) {
            respStr = "Dify API 无返回流，HTTP 状态码：" + code;
        } else {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(rawStream, StandardCharsets.UTF_8))) {
                respStr = reader.lines().collect(Collectors.joining());
            }
        }

        if (code < 200 || code >= 300) {
            throw new IOException("Dify API返回错误: HTTP " + code + "，响应: " + respStr);
        }

        // 6. 解析并保存
        return parseAndSave(respStr, nickname,msg, appDO);
    }

    private ChatMessageRespVO parseAndSave(String jsonStr, String nickname, ChatMessageDO msg,  ChatAppDO appDO) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        String did = json.getString("conversation_id");

        // 6.1 本地如果尚未存 Dify 的 conversation_id，则更新
        ChatSessionDO session = chatSessionMapper.selectOne(new LambdaQueryWrapperX<ChatSessionDO>().eq(ChatSessionDO::getDifyConversationId, did));
        if (session == null) {
            session = new ChatSessionDO();
            session.setName(msg.getContent());
            session.setUserId(nickname);
            session.setDifyConversationId(did);
            session.setAppId(appDO.getId());
            chatSessionMapper.insert(session);
            // ======== 补充：从 Dify 获取会话名称（同步 + 异步）=======
//            asyncUpdateSessionName(did, session.getId());

        }
        chatMessageMapper.updateById(msg.setDifyConversationId(did).setSessionId(session.getId()));
        JSONObject metadata = json.getJSONObject("metadata");
        String metadataStr = metadata.toJSONString();
        // 6.2 保存消息
        ChatMessageDO m = new ChatMessageDO();
        m.setDifyConversationId(did);
        m.setSessionId(session.getId());
        m.setUserId(nickname);
        m.setDifyMessageId(json.getString("message_id"));
        m.setContent(json.getString("answer"));
        m.setRole("assistant");
        m.setMetadataJson(metadataStr);
        chatMessageMapper.insert(m);

        // 7. 组装 VO 返回
        ChatMessageRespVO vo = new ChatMessageRespVO();
        vo.setSessionId(session.getId());
        vo.setDifyConversationId(did);
        vo.setUserId(nickname);
        vo.setDifyMessageId(m.getDifyMessageId());
        vo.setContent(m.getContent());
        vo.setRole(m.getRole());
        vo.setMessageTime(m.getCreateTime());
        vo.setStatus("completed");
        vo.setResponseJson(jsonStr);
        vo.setMetadataJson(metadata);
        return vo;
    }

    @Override
    public List<ChatMessageDO> getChatMessageList(ChatMessagePageReqVO reqVO) {

        List<ChatMessageDO> messageDOList = chatMessageMapper.selectList(new LambdaQueryWrapperX<ChatMessageDO>()
                .eqIfPresent(ChatMessageDO::getSessionId, reqVO.getSessionId())
                .eqIfPresent(ChatMessageDO::getUserId, reqVO.getUserId())
                .eqIfPresent(ChatMessageDO::getRole, reqVO.getRole())
                .eqIfPresent(ChatMessageDO::getContent, reqVO.getContent())
                .betweenIfPresent(ChatMessageDO::getMessageTime, reqVO.getMessageTime())
                .eqIfPresent(ChatMessageDO::getDifyMessageId, reqVO.getDifyMessageId())
                .eqIfPresent(ChatMessageDO::getDifyTaskId, reqVO.getDifyTaskId())
                .eqIfPresent(ChatMessageDO::getDifyEvent, reqVO.getDifyEvent())
                .eqIfPresent(ChatMessageDO::getDifyConversationId, reqVO.getDifyConversationId())
                .eqIfPresent(ChatMessageDO::getCreatedTimestamp, reqVO.getCreatedTimestamp())
                .eqIfPresent(ChatMessageDO::getAgentThought, reqVO.getAgentThought())
                .eqIfPresent(ChatMessageDO::getAgentObservation, reqVO.getAgentObservation())
                .eqIfPresent(ChatMessageDO::getAgentTool, reqVO.getAgentTool())
                .eqIfPresent(ChatMessageDO::getAgentToolInput, reqVO.getAgentToolInput())
                .eqIfPresent(ChatMessageDO::getFileIds, reqVO.getFileIds())
                .eqIfPresent(ChatMessageDO::getFileUrls, reqVO.getFileUrls())
                .eqIfPresent(ChatMessageDO::getStatus, reqVO.getStatus())
                .eqIfPresent(ChatMessageDO::getIsVisible, reqVO.getIsVisible())
                .eqIfPresent(ChatMessageDO::getMetadataJson, reqVO.getMetadataJson())
                .eqIfPresent(ChatMessageDO::getUsageJson, reqVO.getUsageJson())
                .eqIfPresent(ChatMessageDO::getResponseJson, reqVO.getResponseJson())
                .betweenIfPresent(ChatMessageDO::getCreateTime, reqVO.getCreateTime())
                .orderByAsc(ChatMessageDO::getId));
        return messageDOList;
    }





    @Override
    public Long createChatMessage(ChatMessageSaveReqVO createReqVO) {
        // 插入
        ChatMessageDO chatMessage = BeanUtils.toBean(createReqVO, ChatMessageDO.class);
        chatMessageMapper.insert(chatMessage);
        // 返回
        return chatMessage.getId();
    }

    @Override
    public void updateChatMessage(ChatMessageSaveReqVO updateReqVO) {
        // 校验存在
        validateChatMessageExists(updateReqVO.getId());
        // 更新
        ChatMessageDO updateObj = BeanUtils.toBean(updateReqVO, ChatMessageDO.class);
        chatMessageMapper.updateById(updateObj);
    }

    @Override
    public void deleteChatMessage(Long id) {
        // 校验存在
        validateChatMessageExists(id);
        // 删除
        chatMessageMapper.deleteById(id);
    }

    private void validateChatMessageExists(Long id) {
        if (chatMessageMapper.selectById(id) == null) {
            throw exception(CHAT_MESSAGE_NOT_EXISTS);
        }
    }

    @Override
    public ChatMessageDO getChatMessage(Long id) {
        return chatMessageMapper.selectById(id);
    }

    @Override
    public PageResult<ChatMessageDO> getChatMessagePage(ChatMessagePageReqVO pageReqVO) {
        return chatMessageMapper.selectPage(pageReqVO);
    }

}