/**
 * @ProjectName: 智慧评标-主观分助手
 * @Package: com.zhpb.gdyd_zhpb_zgf.service.impl
 * @ClassName: QaServiceImpl
 * @Description: 智能问答服务实现
 * @Author: 张志锋
 * @Date: 2025-11-03
 * @Version: 1.0
 * @Copyright: © 2025 智慧评标-主观分助手
 */
package com.zhpb.gdyd_zhpb_zgf.service.impl;

import com.alibaba.fastjson2.JSON;
import com.zhpb.gdyd_zhpb_zgf.context.ModelRequestContextHolder;
import com.zhpb.gdyd_zhpb_zgf.dto.QaHistoryResponse;
import com.zhpb.gdyd_zhpb_zgf.dto.QaRequest;
import com.zhpb.gdyd_zhpb_zgf.dto.QaResponse;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.File;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.PromptTemplate;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.QaMessage;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.QaSession;
import com.zhpb.gdyd_zhpb_zgf.entity.pgsql.PdfVector;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.FileRepository;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.PromptTemplateRepository;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.QaMessageRepository;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.QaSessionRepository;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.SupplierRepository;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.Supplier;
import com.zhpb.gdyd_zhpb_zgf.repository.pgsql.PdfVectorRepository;
import com.zhpb.gdyd_zhpb_zgf.service.AIModelService;
import com.zhpb.gdyd_zhpb_zgf.service.QaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 智能问答服务实现
 */
@Service
public class QaServiceImpl implements QaService {

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

    @Autowired
    private FileRepository fileRepository;

    @Autowired
    private SupplierRepository supplierRepository;

    @Autowired
    private PromptTemplateRepository promptTemplateRepository;

    @Autowired
    private QaSessionRepository qaSessionRepository;

    @Autowired
    private QaMessageRepository qaMessageRepository;

    @Autowired
    private AIModelService aiModelService;

    @Autowired
    private PdfVectorRepository pdfVectorRepository;

    @Value("${vectorize.base-url:http://localhost:8001}")
    private String vectorizeBaseUrl;

    @Value("${deepseek.api-key:}")
    private String deepseekApiKey;

    @Value("${deepseek.api-url:https://api.deepseek.com/v1/chat/completions}")
    private String deepseekApiUrl;

    @Override
    public QaHistoryResponse.SessionsData getSessionHistory(String projectId, String userId) {
        logger.info("查询历史会话: projectId={}, userId={}", projectId, userId);

        List<QaSession> sessions = qaSessionRepository.findByProjectIdAndUserIdOrderByStartTimeDesc(projectId, userId);

        List<QaHistoryResponse.SessionInfo> sessionInfos = sessions.stream()
            .map(session -> {
                QaHistoryResponse.SessionInfo info = new QaHistoryResponse.SessionInfo();
                info.setSessionId(session.getSessionId());
                info.setStartTime(session.getStartTime().toString());
                info.setFirstQuery(session.getFirstQuery());

                // 获取该会话最后一次引用的文件
                try {
                    QaMessage lastFileMsg = qaMessageRepository.findLastMessageWithFiles(session.getSessionId());
                    if (lastFileMsg != null && lastFileMsg.getFileIds() != null) {
                        List<String> fileIds = JSON.parseArray(lastFileMsg.getFileIds(), String.class);
                        if (fileIds != null && !fileIds.isEmpty()) {
                            info.setFileIds(fileIds);
                            
                            // 获取文件名和供应商名
                            List<String> fileNames = new ArrayList<>();
                            List<String> supplierNames = new ArrayList<>();
                            List<String> supplierIds = new ArrayList<>();
                            
                            for (String rawFileId : fileIds) {
                                String fileId = rawFileId != null ? rawFileId.trim() : "";
                                if (fileId.isEmpty()) continue;

                                Optional<File> fileOpt = fileRepository.findByFileId(fileId);
                                if (fileOpt.isPresent()) {
                                    File file = fileOpt.get();
                                    fileNames.add(file.getFileName());
                                    
                                    // 获取供应商名称
                                    String supplierName = "未知供应商";
                                    String supplierId = file.getSupplierId();
                                    
                                    if (supplierId != null) {
                                        Supplier supplier = supplierRepository.findBySupplierId(supplierId);
                                        if (supplier != null && supplier.getSupplierName() != null) {
                                            supplierName = supplier.getSupplierName();
                                        } else {
                                            supplierName = supplierId;
                                        }
                                    }
                                    supplierNames.add(supplierName);
                                    supplierIds.add(supplierId);
                                } else {
                                    logger.warn("未找到文件记录: fileId={}", fileId);
                                    fileNames.add("未知文件");
                                    supplierNames.add("未知供应商");
                                    supplierIds.add("");
                                }
                            }
                            
                            info.setFileNames(fileNames);
                            info.setSupplierNames(supplierNames);
                            info.setSupplierIds(supplierIds);
                        }
                    }
                } catch (Exception e) {
                    logger.warn("获取会话文件信息失败: sessionId={}, error={}", session.getSessionId(), e.getMessage());
                }

                return info;
            })
            .toList();

        QaHistoryResponse.SessionsData data = new QaHistoryResponse.SessionsData();
        data.setSessions(sessionInfos);

        return data;
    }

    @Override
    public QaHistoryResponse.MessagesData getMessageHistory(String sessionId) {
        logger.info("查询会话消息历史: sessionId={}", sessionId);

        List<QaMessage> messages = qaMessageRepository.findBySessionIdOrderByTimestampAsc(sessionId);

        List<QaHistoryResponse.MessageInfo> messageInfos = messages.stream()
            .map(message -> {
                QaHistoryResponse.MessageInfo info = new QaHistoryResponse.MessageInfo();
                info.setMessageId(message.getMessageId());
                info.setSender(message.getSender());
                info.setContent(message.getContent());
                info.setTimestamp(message.getTimestamp().toString());

                // 解析sources JSON
                if (message.getSources() != null && !message.getSources().isEmpty()) {
                    try {
                        info.setSources(JSON.parse(message.getSources()));
                    } catch (Exception e) {
                        logger.warn("解析消息sources失败: messageId={}", message.getMessageId());
                        info.setSources(null);
                    }
                }

                // 解析fileIds JSON
                if (message.getFileIds() != null && !message.getFileIds().isEmpty()) {
                    try {
                        info.setFileIds(JSON.parseArray(message.getFileIds(), String.class));
                    } catch (Exception e) {
                        logger.warn("解析消息fileIds失败: messageId={}", message.getMessageId());
                        info.setFileIds(null);
                    }
                }

                return info;
            })
            .toList();

        QaHistoryResponse.MessagesData data = new QaHistoryResponse.MessagesData();
        data.setSessionId(sessionId);
        data.setMessages(messageInfos);

        return data;
    }

    @Override
    public QaResponse.QaData sendMessage(QaRequest request) {
        logger.info("开始处理智能问答请求: projectId={}, userId={}, query={}",
                request.getProjectId(), request.getUserId(), request.getQuery());

        QaResponse.QaData response = new QaResponse.QaData();

        String userQuery = request.getQuery() != null ? request.getQuery().trim() : "";
        if (userQuery.isEmpty()) {
            logger.warn("收到空查询，请求被拒绝");
            response.setAnswer("请先输入要咨询的问题，再提交请求。");
            response.setSources(new ArrayList<>());
            response.setSessionId(null);
            response.setMessageId(null);
            return response;
        }

        try {
            // 会话管理：如果 sessionId 为空则创建新会话，如果有值则使用该值
            String sessionId;
            
            if (request.getSessionId() != null && !request.getSessionId().trim().isEmpty()) {
                // 如果请求中提供了 sessionId，直接使用（不创建新会话）
                sessionId = request.getSessionId().trim();
                logger.info("使用已有会话ID: {}", sessionId);
            } else {
                // 如果 sessionId 为空，创建新会话
                sessionId = "session-" + UUID.randomUUID().toString().replace("-", "").substring(0, 12);
                logger.info("创建新会话: {}", sessionId);
            }
            
            String userMessageId = "user-msg-" + UUID.randomUUID().toString().replace("-", "").substring(0, 12);
            String aiMessageId = "msg-" + UUID.randomUUID().toString().replace("-", "").substring(0, 12);

            response.setSessionId(sessionId);
            response.setMessageId(aiMessageId);

            // 获取相关文件信息
            List<String> fileIds = request.getFileIds();
            
            // 如果请求未指定文件，尝试从会话历史中获取最后一次使用的文件（上下文继承）
            if ((fileIds == null || fileIds.isEmpty()) && sessionId != null) {
                try {
                    QaMessage lastFileMsg = qaMessageRepository.findLastMessageWithFiles(sessionId);
                    if (lastFileMsg != null && lastFileMsg.getFileIds() != null) {
                        List<String> historyFileIds = JSON.parseArray(lastFileMsg.getFileIds(), String.class);
                        if (historyFileIds != null && !historyFileIds.isEmpty()) {
                            fileIds = historyFileIds;
                            logger.info("使用会话历史文件上下文: sessionId={}, fileIds={}", sessionId, fileIds);
                        }
                    }
                } catch (Exception e) {
                    logger.warn("获取会话历史文件上下文失败: sessionId={}", sessionId);
                }
            }

            if (fileIds == null) {
                fileIds = Collections.emptyList();
            }

            List<File> files = fileIds.stream()
                .map(fileId -> fileRepository.findByFileId(fileId))
                .filter(Optional::isPresent)
                .map(Optional::get)
                .toList();

            // 获取提示词模板
            PromptTemplate promptTemplate = getActivePromptTemplate("qa");
            if (promptTemplate == null) {
                logger.warn("未找到启用的智能问答提示词模板");
                response.setAnswer("抱歉，系统配置不完整，无法处理您的请求。");
                response.setSources(new ArrayList<>());
                return response;
            }

            StringBuilder documentContent = new StringBuilder();
            List<QaResponse.SourceInfo> sources = new ArrayList<>();

            if (!files.isEmpty()) {
                // 如果有文件引用，构建文档内容
                for (File file : files) {
                    documentContent.append("文件: ").append(file.getFileName()).append("\n");
                    documentContent.append("供应商: ").append(getSupplierName(file)).append("\n");

                    String fileContent = loadVectorContentByFileId(file.getFileId());
                    if (fileContent == null || fileContent.isBlank()) {
                        fileContent = "未能从向量数据库读取该文件的正文内容，请确认该文件已成功向量化。";
                    }
                    documentContent.append("内容: ").append(fileContent).append("\n\n");

                    // 添加来源信息
                    QaResponse.SourceInfo source = new QaResponse.SourceInfo();
                    source.setFileId(file.getFileId());
                    source.setFileName(file.getFileName());
                    source.setVendorName(getSupplierName(file));
                    source.setSimilarity(0.8); // 简化处理
                    sources.add(source);
                }
            } else {
                // 如果没有文件引用，直接使用大模型回答
                logger.info("没有文件引用，直接使用大模型回答问题");
                documentContent.append("请直接回答用户的问题，无需引用任何文档内容。\n\n用户问题：").append(userQuery);
            }

            // 调用DeepSeek API
            String answer = callDeepSeekApi(userQuery, documentContent.toString(), promptTemplate.getPromptContent());

            response.setAnswer(answer);
            response.setSources(sources);

            // 持久化会话和消息
            saveQaHistory(sessionId, request.getProjectId(), request.getUserId(), userQuery,
                         fileIds, answer, sources, userMessageId, aiMessageId);

            logger.info("智能问答处理完成: sessionId={}, aiMessageId={}", sessionId, aiMessageId);

        } catch (Exception e) {
            logger.error("智能问答处理失败", e);
            response.setAnswer("抱歉，处理您的问题时出现系统错误，请稍后重试。");
            response.setSources(new ArrayList<>());
        }

        return response;
    }

    /**
     * 获取启用的提示词模板
     */
    private PromptTemplate getActivePromptTemplate(String templateType) {
        List<PromptTemplate> templates = promptTemplateRepository.findActiveByTemplateType(templateType);
        return templates.isEmpty() ? null : templates.get(0);
    }

    /**
     * 获取供应商名称
     */
    private String getSupplierName(File file) {
        // 简化处理，实际应该从Supplier表中查询
        return file.getSupplierId() != null ? "供应商-" + file.getSupplierId() : "未知供应商";
    }

    /**
     * 持久化QA历史记录
     */
    private void saveQaHistory(String sessionId, String projectId, String userId, String query,
                              List<String> fileIds, String answer, List<QaResponse.SourceInfo> sources,
                              String userMessageId, String aiMessageId) {
        try {
            logger.info("开始保存QA历史记录: sessionId={}, projectId={}, userId={}", 
                sessionId, projectId, userId);
            
            // 检查会话是否存在
            QaSession session = qaSessionRepository.findBySessionId(sessionId).orElse(null);

            if (session == null) {
                // 创建新会话
                logger.info("会话不存在，创建新会话: sessionId={}", sessionId);
                session = new QaSession();
                session.setSessionId(sessionId);
                session.setProjectId(projectId);
                session.setUserId(userId);
                session.setFirstQuery(query);
                session.setStartTime(java.time.LocalDateTime.now());
                session.setMessageCount(0);
                session.setStatus("active");
                
                try {
                    session = qaSessionRepository.save(session);
                    logger.info("新QA会话创建成功: sessionId={}, id={}", sessionId, session.getId());
                } catch (Exception e) {
                    logger.error("保存QA会话失败: sessionId={}, error={}", sessionId, e.getMessage(), e);
                    throw e;
                }
            } else {
                logger.info("找到已存在的会话: sessionId={}, messageCount={}", 
                    sessionId, session.getMessageCount());
            }

            // 保存用户消息
            logger.info("开始保存用户消息: messageId={}", userMessageId);
            QaMessage userMessage = new QaMessage();
            userMessage.setMessageId(userMessageId);
            userMessage.setSessionId(sessionId);
            userMessage.setSender("user");
            userMessage.setContent(query);
            userMessage.setFileIds(JSON.toJSONString(fileIds));
            userMessage.setTimestamp(java.time.LocalDateTime.now());
            
            try {
                QaMessage savedUserMessage = qaMessageRepository.save(userMessage);
                logger.info("用户消息保存成功: messageId={}, id={}", userMessageId, savedUserMessage.getId());
            } catch (Exception e) {
                logger.error("保存用户消息失败: messageId={}, error={}", userMessageId, e.getMessage(), e);
                throw e;
            }

            // 保存AI回复消息
            logger.info("开始保存AI回复消息: messageId={}", aiMessageId);
            QaMessage aiMessage = new QaMessage();
            aiMessage.setMessageId(aiMessageId);
            aiMessage.setSessionId(sessionId);
            aiMessage.setSender("ai");
            aiMessage.setContent(answer);
            aiMessage.setSources(JSON.toJSONString(sources));
            aiMessage.setFileIds(JSON.toJSONString(fileIds));
            aiMessage.setTimestamp(java.time.LocalDateTime.now());
            
            try {
                QaMessage savedAiMessage = qaMessageRepository.save(aiMessage);
                logger.info("AI回复消息保存成功: messageId={}, id={}", aiMessageId, savedAiMessage.getId());
            } catch (Exception e) {
                logger.error("保存AI回复消息失败: messageId={}, error={}", aiMessageId, e.getMessage(), e);
                throw e;
            }

            // 更新会话统计信息
            logger.info("开始更新会话统计信息: sessionId={}", sessionId);
            session.setLastMessageTime(java.time.LocalDateTime.now());
            session.setMessageCount(session.getMessageCount() + 2);
            
            try {
                qaSessionRepository.save(session);
                logger.info("会话统计信息更新成功: sessionId={}, 新消息数={}", 
                    sessionId, session.getMessageCount());
            } catch (Exception e) {
                logger.error("更新会话统计信息失败: sessionId={}, error={}", sessionId, e.getMessage(), e);
                throw e;
            }
            
            logger.info("QA历史记录保存完成: sessionId={}, userMessageId={}, aiMessageId={}", 
                sessionId, userMessageId, aiMessageId);

        } catch (Exception e) {
            logger.error("保存QA历史记录失败: sessionId={}, projectId={}, userId={}, error={}", 
                sessionId, projectId, userId, e.getMessage(), e);
            logger.error("异常堆栈信息:", e);
            // 不影响主要业务流程，但记录详细错误
        }
    }

    /**
     * 从向量数据库中加载文件内容
     */
    private String loadVectorContentByFileId(String fileId) {
        try {
            List<PdfVector> vectors = pdfVectorRepository.findByFileId(fileId);
            if (vectors != null && !vectors.isEmpty()) {
                String content = vectors.get(0).getContent();
                if (content != null && !content.isBlank()) {
                    return truncateContent(content);
                }
            }
        } catch (Exception e) {
            logger.warn("读取向量数据库内容失败: fileId={}, error={}", fileId, e.getMessage());
        }
        return null;
    }

    private String truncateContent(String content) {
        String normalized = content.trim();
        int maxLength = 2000;
        if (normalized.length() > maxLength) {
            return normalized.substring(0, maxLength) + "...（内容已截断）";
        }
        return normalized;
    }

    /**
     * 调用AI模型API
     */
    private String callDeepSeekApi(String query, String documentContent, String promptTemplate) {
        try {
            logger.info("开始调用AI模型API");

            // 构建提示词
            String systemPrompt = promptTemplate
                    .replace("{query}", query)
                    .replace("{document_content}", documentContent);

            // 强制要求纯文本格式
            systemPrompt += "\n\n请注意：请仅返回纯文本格式，不要使用Markdown、HTML或其他标记语言（如 **加粗**、# 标题等）。";

            // 构造用户消息，确保大模型收到明确的提问上下文
            String userMessage = buildUserMessage(query, documentContent);

            ModelRequestContextHolder.setRequestSource("QA_CHAT");
            String response;
            try {
                response = aiModelService.generateResponse(systemPrompt, userMessage);
            } finally {
                ModelRequestContextHolder.clear();
            }

            if (response != null && !response.trim().isEmpty()) {
                logger.info("AI模型返回回答，长度: {}", response.length());
                return response.trim();
            }

            logger.warn("AI模型返回空响应");
            return "抱歉，AI服务响应为空，请稍后重试。";

        } catch (Exception e) {
            logger.error("调用AI模型API失败", e);
            return "抱歉，AI服务暂时不可用，请稍后重试。";
        }
    }

    private String buildUserMessage(String query, String documentContent) {
        StringBuilder builder = new StringBuilder();
        if (documentContent != null && !documentContent.isBlank()) {
            builder.append(documentContent.trim());
        }
        if (query != null && !query.isBlank()) {
            if (builder.length() > 0) {
                builder.append("\n\n");
            }
            builder.append("用户问题：").append(query.trim());
        }
        return builder.toString();
    }
}
