package top.tqx.demo_1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.tqx.demo_1.dto.RagRequest;
import top.tqx.demo_1.entity.ChatMessage;
import top.tqx.demo_1.entity.ChatReference;
import top.tqx.demo_1.entity.ChatSession;
import top.tqx.demo_1.entity.Image;
import top.tqx.demo_1.mapper.ChatMessageMapper;
import top.tqx.demo_1.mapper.ChatReferenceMapper;
import top.tqx.demo_1.mapper.ChatSessionMapper;
import top.tqx.demo_1.service.ChatService;
import top.tqx.demo_1.service.ImageService;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Slf4j
@Service
public class ChatServiceImpl implements ChatService {

    @Autowired
    private ChatSessionMapper chatSessionMapper;

    @Autowired
    private ChatMessageMapper chatMessageMapper;

    @Autowired
    private ChatReferenceMapper chatReferenceMapper;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ImageService imageService;

    // Nginx 图片访问前缀（从配置文件读取）
    @Value("${file.upload.url-prefix:/files/}")
    private String imageUrlPrefix;

    // 图片访问路径（兼容旧版，使用现有的图片服务接口 /api/image/{imageId}/data）
    private static final String IMAGE_ACCESS_PATH = "/api/image/";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatSession createSession(Long userId, String sessionId) {
        ChatSession session = new ChatSession();
        session.setSessionId(sessionId != null && !sessionId.isEmpty() ? sessionId : generateSessionId());
        session.setUserId(userId);
        session.setSummary("");
        session.setCreateTime(LocalDateTime.now());
        chatSessionMapper.insert(session);
        log.info("创建会话: sessionId={}, userId={}", session.getSessionId(), userId);
        return session;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatSession getOrCreateSession(Long userId, String sessionId) {
        if (sessionId != null && !sessionId.isEmpty()) {
            LambdaQueryWrapper<ChatSession> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ChatSession::getSessionId, sessionId)
                   .eq(ChatSession::getUserId, userId);
            ChatSession existing = chatSessionMapper.selectOne(wrapper);
            if (existing != null) {
                return existing;
            }
        }
        return createSession(userId, sessionId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatSession updateSessionSummary(Long sessionId, String summary) {
        ChatSession session = chatSessionMapper.selectById(sessionId);
        if (session != null) {
            session.setSummary(summary);
            chatSessionMapper.updateById(session);
            log.info("更新会话摘要: sessionId={}, summary={}", sessionId, summary);
        }
        return session;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatMessage saveUserMessage(Long sessionId, String content, String kbPaths) {
        ChatMessage message = new ChatMessage();
        message.setConversationId(sessionId);
        message.setRole("user");
        message.setContent(content);
        message.setMessageType("text");
        message.setIsFinished(1);
        message.setKbPaths(kbPaths);
        message.setCreateTime(LocalDateTime.now());
        chatMessageMapper.insert(message);
        log.info("保存用户消息: messageId={}, sessionId={}, contentLength={}", message.getId(), sessionId, content.length());
        return message;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatMessage saveAssistantMessage(Long sessionId, String content, String answer, String kbPaths, String messageType, Integer isFinished, Long durationMs, String images, String sources) {
        if (content == null || content.isEmpty()) {
            log.warn("助手消息内容为空，跳过保存");
            return null;
        }
        
        if (answer == null || answer.isEmpty()) {
            log.warn("助手回答内容为空，跳过保存");
            return null;
        }
        
        ChatMessage existing = chatMessageMapper.findAssistantMessageByContent(sessionId, content);
        if (existing != null) {
            log.warn("相同内容的助手消息已存在，跳过保存: sessionId={}, content={}", sessionId, content);
            return existing;
        }
        
        ChatMessage message = new ChatMessage();
        message.setConversationId(sessionId);
        message.setRole("assistant");
        message.setContent(content);
        message.setAnswer(answer);
        message.setKbPaths(kbPaths);
        message.setMessageType(messageType != null ? messageType : "text");
        message.setIsFinished(isFinished != null ? isFinished : 1);
        message.setDurationMs(durationMs);
        message.setImages(images);
        message.setSources(sources);
        message.setCreateTime(LocalDateTime.now());
        chatMessageMapper.insert(message);
        log.info("保存助手消息: messageId={}, sessionId={}, type={}, finished={}, duration={}ms, images={}, sources={}", message.getId(), sessionId, messageType, isFinished, durationMs, images != null ? "[" + images.length() + " chars]" : "null", sources != null ? "[" + sources.length() + " chars]" : "null");
        return message;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatReference saveReference(Long messageId, String chunkId, String docPath, String docName, Integer page, String excerpt, Double score) {
        ChatReference reference = new ChatReference();
        reference.setMessageId(messageId);
        reference.setChunkId(chunkId);
        reference.setDocPath(docPath);
        reference.setDocName(docName);
        reference.setPage(page);
        reference.setExcerpt(excerpt);
        reference.setCreateTime(LocalDateTime.now());
        chatReferenceMapper.insert(reference);
        log.info("保存引用: referenceId={}, messageId={}, docName={}", reference.getId(), messageId, docName);
        return reference;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ChatReference> saveReferences(Long messageId, List<ChatReference> references) {
        List<ChatReference> saved = new ArrayList<>();
        for (ChatReference ref : references) {
            ref.setMessageId(messageId);
            ref.setCreateTime(LocalDateTime.now());
            chatReferenceMapper.insert(ref);
            saved.add(ref);
        }
        log.info("批量保存引用: messageId={}, count={}", messageId, saved.size());
        return saved;
    }

    @Override
    public List<ChatSession> getUserSessions(Long userId) {
        LambdaQueryWrapper<ChatSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChatSession::getUserId, userId)
               .orderByDesc(ChatSession::getCreateTime);
        return chatSessionMapper.selectList(wrapper);
    }

    @Override
    public List<ChatMessage> getSessionMessages(String sessionId) {
        log.info("开始获取会话消息，sessionId={}", sessionId);
        
        // 先通过 sessionId 查找会话，获取会话的 id
        LambdaQueryWrapper<ChatSession> sessionWrapper = new LambdaQueryWrapper<>();
        sessionWrapper.eq(ChatSession::getSessionId, sessionId);
        ChatSession session = chatSessionMapper.selectOne(sessionWrapper);
        
        if (session == null) {
            log.warn("未找到会话，sessionId={}", sessionId);
            return new ArrayList<>();
        }
        
        log.info("找到会话，id={}, sessionId={}", session.getId(), sessionId);
        
        // 然后通过会话 id 查找消息
        LambdaQueryWrapper<ChatMessage> messageWrapper = new LambdaQueryWrapper<>();
        messageWrapper.eq(ChatMessage::getConversationId, session.getId())
               .orderByAsc(ChatMessage::getCreateTime);
        List<ChatMessage> messages = chatMessageMapper.selectList(messageWrapper);
        
        log.info("查询到 {} 条消息", messages.size());
        
        // 为每条消息关联查询引用信息并处理图片URL
        for (ChatMessage message : messages) {
            // 如果是AI助手消息，关联查询引用信息
            if ("assistant".equals(message.getRole())) {
                List<ChatReference> references = getMessageReferences(message.getId());
                log.info("消息 id={} 有 {} 条引用", message.getId(), references.size());
                
                // 首先从 image 类型的引用中提取图片信息
                extractImagesFromReferences(message, references);
                
                // 将引用信息添加到消息中（通过sources字段扩展）
                enrichMessageWithReferences(message, references);
            }
            
            // 处理图片URL转换
            processImageUrls(message);
        }
        
        log.info("会话消息处理完成，共 {} 条消息", messages.size());
        return messages;
    }
    
    /**
     * 从引用中提取 image 类型的图片信息，添加到消息的 images 字段
     */
    private void extractImagesFromReferences(ChatMessage message, List<ChatReference> references) {
        log.info("开始从引用中提取图片，messageId={}", message.getId());
        
        try {
            List<Map<String, Object>> imagesList = new ArrayList<>();
            
            // 如果消息已经有图片数据，先解析出来
            if (message.getImages() != null && !message.getImages().isEmpty()) {
                imagesList = objectMapper.readValue(
                    message.getImages(), 
                    new TypeReference<List<Map<String, Object>>>() {}
                );
                log.info("消息已有 {} 张图片", imagesList.size());
            }
            
            // 查找 chunkType 为 'image' 的引用
            for (ChatReference reference : references) {
                if ("image".equals(reference.getChunkType())) {
                    log.info("找到 image 类型的引用: docName={}, page={}, chunkId={}", 
                            reference.getDocName(), reference.getPage(), reference.getChunkId());
                    
                    // 从 context_image 表中查找对应的图片
                    List<Image> foundImages = imageService.findImagesByReference(
                            reference.getDocName(), 
                            reference.getPage(), 
                            reference.getChunkId()
                    );
                    
                    if (foundImages != null && !foundImages.isEmpty()) {
                        log.info("从引用中找到 {} 张图片", foundImages.size());
                        
                        for (Image image : foundImages) {
                            Map<String, Object> imageMap = new HashMap<>();
                            imageMap.put("image_id", image.getImageId());
                            imageMap.put("doc_name", image.getSource());
                            imageMap.put("page", image.getPage());
                            
                            // 检查是否已经有这个 image_id 的图片了，避免重复
                            boolean alreadyExists = false;
                            for (Map<String, Object> existingImg : imagesList) {
                                if (image.getImageId().equals(existingImg.get("image_id"))) {
                                    alreadyExists = true;
                                    break;
                                }
                            }
                            
                            if (!alreadyExists) {
                                imagesList.add(imageMap);
                                log.info("添加图片到消息: imageId={}", image.getImageId());
                            }
                        }
                    } else {
                        log.warn("未能从引用中找到对应的图片");
                    }
                }
            }
            
            // 更新消息的 images 字段
            if (!imagesList.isEmpty()) {
                String imagesJson = objectMapper.writeValueAsString(imagesList);
                message.setImages(imagesJson);
                log.info("成功更新消息的 images 字段，共 {} 张图片，数据: {}", 
                        imagesList.size(), 
                        imagesJson.substring(0, Math.min(300, imagesJson.length())));
            }
            
        } catch (IOException e) {
            log.error("从引用中提取图片失败: messageId={}, error={}", message.getId(), e.getMessage(), e);
        }
    }
    
    /**
     * 处理消息中的图片URL，转换为Nginx静态路径URL
     */
    private void processImageUrls(ChatMessage message) {
        log.info("开始处理图片URL，messageId={}, images={}", 
                 message.getId(), 
                 message.getImages() != null ? message.getImages().substring(0, Math.min(200, message.getImages().length())) : "null");
        
        if (message.getImages() == null || message.getImages().isEmpty()) {
            log.debug("消息没有图片数据，跳过处理");
            return;
        }
        
        try {
            List<Map<String, Object>> images = objectMapper.readValue(
                message.getImages(), 
                new TypeReference<List<Map<String, Object>>>() {});
            
            log.info("解析到 {} 张图片", images.size());
            
            boolean updated = false;
            for (int i = 0; i < images.size(); i++) {
                Map<String, Object> image = images.get(i);
                String imageId = (String) image.get("image_id");
                log.info("处理第 {} 张图片，imageId={}, 现有数据={}", 
                         i + 1, imageId, image);
                
                if (imageId != null) {
                    String nginxUrl = findNginxImageUrl(imageId);
                    if (nginxUrl != null) {
                        image.put("url", nginxUrl);
                        updated = true;
                        log.info("✅ 成功转换图片URL: imageId={}, url={}", imageId, nginxUrl);
                    } else {
                        // 如果没有找到Nginx URL，提供一个回退URL
                        String fallbackUrl = getFallbackImageUrl(imageId);
                        image.put("url", fallbackUrl);
                        updated = true;
                        log.warn("⚠️ 使用回退图片URL: imageId={}, url={}", imageId, fallbackUrl);
                    }
                }
            }
            
            if (updated) {
                String newImagesJson = objectMapper.writeValueAsString(images);
                message.setImages(newImagesJson);
                log.info("✅ 图片URL处理完成，更新后的数据: {}", 
                         newImagesJson.substring(0, Math.min(300, newImagesJson.length())));
            } else {
                log.info("没有需要更新的图片URL");
            }
        } catch (IOException e) {
            log.error("❌ 处理图片URL失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 获取回退的图片URL
     */
    private String getFallbackImageUrl(String imageId) {
        // 使用API接口作为回退方案
        return "/api/image/" + imageId + "/data";
    }
    
    /**
     * 根据imageId查找本地图片，返回Nginx访问路径
     */
    private String findNginxImageUrl(String imageId) {
        log.info("🔍 开始查找图片Nginx URL，imageId={}", imageId);
        try {
            // 从数据库查询图片记录
            log.debug("尝试查询原始imageId: {}", imageId);
            Image image = imageService.getImageByImageId(imageId);
            
            // 如果没找到，尝试带.jpg后缀
            if (image == null && !imageId.toLowerCase().endsWith(".jpg")) {
                String jpgImageId = imageId + ".jpg";
                log.debug("未找到，尝试带.jpg后缀: {}", jpgImageId);
                image = imageService.getImageByImageId(jpgImageId);
            }
            
            // 如果还没找到，尝试去掉后缀（如果有）
            if (image == null) {
                String imageIdWithoutExt = removeExtension(imageId);
                if (!imageIdWithoutExt.equals(imageId)) {
                    log.debug("仍未找到，尝试去掉后缀: {}", imageIdWithoutExt);
                    image = imageService.getImageByImageId(imageIdWithoutExt);
                }
            }
            
            // 找到图片记录，提取文件名并构造Nginx URL
            if (image != null) {
                log.info("✅ 找到图片记录，imageId={}, 数据库ID={}, path={}", 
                         imageId, image.getId(), image.getPath());
                
                if (image.getPath() != null) {
                    String dbPath = image.getPath();
                    
                    // 从路径中提取文件名
                    String filename = extractFilenameFromPath(dbPath);
                    if (filename != null) {
                        // 构造Nginx URL: /files/img/{filename}
                        String nginxUrl = imageUrlPrefix + "img/" + filename;
                        log.info("✅ 成功构造Nginx URL: {}", nginxUrl);
                        return nginxUrl;
                    } else {
                        log.warn("⚠️ 无法从路径中提取文件名: {}", dbPath);
                    }
                } else {
                    log.warn("⚠️ 图片记录中path字段为空");
                }
            } else {
                log.warn("⚠️ 数据库中未找到图片记录，imageId={}", imageId);
            }
        } catch (Exception e) {
            log.error("❌ 查找图片Nginx URL失败: imageId={}, error={}", imageId, e.getMessage(), e);
        }
        
        return null;
    }
    
    /**
     * 去掉文件名的扩展名
     */
    private String removeExtension(String filename) {
        if (filename == null) {
            return null;
        }
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0) {
            return filename.substring(0, lastDotIndex);
        }
        return filename;
    }
    
    /**
     * 从文件路径中提取文件名
     * 支持格式: /app/uploads/img/xxx.jpg 或 /opt/deploy/uploads/img/xxx.jpg
     */
    private String extractFilenameFromPath(String path) {
        if (path == null || path.isEmpty()) {
            return null;
        }
        
        try {
            // 使用Paths处理路径，兼容不同操作系统的分隔符
            Path filePath = Paths.get(path);
            return filePath.getFileName().toString();
        } catch (Exception e) {
            log.debug("从路径提取文件名失败: path={}, error={}", path, e.getMessage());
            
            // 备用方案：字符串分割
            try {
                // 查找最后一个 / 或 \
                int lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
                if (lastSlash >= 0 && lastSlash < path.length() - 1) {
                    return path.substring(lastSlash + 1);
                }
            } catch (Exception ex) {
                log.debug("备用方案提取文件名也失败: {}", ex.getMessage());
            }
        }
        
        return null;
    }
    
    /**
     * 从图片URL中提取图片ID
     * 支持的URL格式示例：
     * - http://localhost:5001/images/dcbee1500209
     * - http://localhost:5001/images/dcbee1500209.jpg
     */
    private String extractImageIdFromUrl(String url) {
        if (url == null || url.isEmpty()) {
            return null;
        }
        
        try {
            // 移除查询参数
            int queryIndex = url.indexOf('?');
            if (queryIndex > 0) {
                url = url.substring(0, queryIndex);
            }
            
            // 获取路径部分
            int pathStart = url.indexOf("/", 8); // 跳过 http:// 或 https://
            if (pathStart < 0) {
                return null;
            }
            
            String path = url.substring(pathStart);
            
            // 分割路径，获取最后一段
            String[] pathParts = path.split("/");
            if (pathParts.length >= 2) {
                return pathParts[pathParts.length - 1];
            }
        } catch (Exception e) {
            log.debug("解析图片URL失败: url={}, error={}", url, e.getMessage());
        }
        
        return null;
    }
    
    /**
     * 将引用信息丰富到消息中
     */
    private void enrichMessageWithReferences(ChatMessage message, List<ChatReference> references) {
        if (references == null || references.isEmpty()) {
            return;
        }
        
        try {
            // 获取现有的sources
            List<Map<String, Object>> sourcesList = new ArrayList<>();
            if (message.getSources() != null && !message.getSources().isEmpty()) {
                sourcesList = objectMapper.readValue(
                    message.getSources(), 
                    new TypeReference<List<Map<String, Object>>>() {});
            }
            
            // 创建引用详情映射
            Map<String, Object> citationsMap = new HashMap<>();
            citationsMap.put("citations", references);
            
            // 如果sources为空，创建一个默认的sources列表
            if (sourcesList.isEmpty()) {
                // 从引用中提取文档信息
                Map<String, Object> sourceInfo = new HashMap<>();
                sourceInfo.put("docName", "引用文档");
                sourceInfo.put("referenceCount", references.size());
                sourcesList.add(sourceInfo);
            }
            
            // 更新sources字段，添加引用详情
            message.setSources(objectMapper.writeValueAsString(sourcesList));
            
            // 不修改answer字段，保持原有内容（不添加引用来源列表）
        } catch (IOException e) {
            log.warn("丰富引用信息失败: {}", e.getMessage());
        }
    }

    @Override
    public List<RagRequest.HistoryItem> getSessionMessagesAsHistory(String sessionId) {
        List<ChatMessage> messages = getSessionMessages(sessionId);
        List<RagRequest.HistoryItem> history = new ArrayList<>();
        for (ChatMessage message : messages) {
            RagRequest.HistoryItem item = new RagRequest.HistoryItem();
            item.setRole(message.getRole());
            item.setContent(message.getContent());
            history.add(item);
        }
        log.info("获取历史记录: sessionId={}, count={}", sessionId, history.size());
        return history;
    }

    @Override
    public List<ChatReference> getMessageReferences(Long messageId) {
        LambdaQueryWrapper<ChatReference> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChatReference::getMessageId, messageId);
        return chatReferenceMapper.selectList(wrapper);
    }

    @Override
    public List<ChatReference> getSessionReferences(String sessionId) {
        // 先通过 sessionId 查找会话，获取会话的 id
        LambdaQueryWrapper<ChatSession> sessionWrapper = new LambdaQueryWrapper<>();
        sessionWrapper.eq(ChatSession::getSessionId, sessionId);
        ChatSession session = chatSessionMapper.selectOne(sessionWrapper);
        
        if (session == null) {
            return new ArrayList<>();
        }
        
        // 查找该会话的所有消息
        LambdaQueryWrapper<ChatMessage> messageWrapper = new LambdaQueryWrapper<>();
        messageWrapper.eq(ChatMessage::getConversationId, session.getId());
        List<ChatMessage> messages = chatMessageMapper.selectList(messageWrapper);
        
        if (messages.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 收集所有消息ID
        List<Long> messageIds = new ArrayList<>();
        for (ChatMessage message : messages) {
            messageIds.add(message.getId());
        }
        
        // 查找所有引用
        LambdaQueryWrapper<ChatReference> referenceWrapper = new LambdaQueryWrapper<>();
        referenceWrapper.in(ChatReference::getMessageId, messageIds);
        return chatReferenceMapper.selectList(referenceWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteSession(String sessionId, Long userId) {
        try {
            // 先通过 sessionId 和 userId 查找会话，确保只能删除自己的会话
            LambdaQueryWrapper<ChatSession> sessionWrapper = new LambdaQueryWrapper<>();
            sessionWrapper.eq(ChatSession::getSessionId, sessionId)
                   .eq(ChatSession::getUserId, userId);
            ChatSession session = chatSessionMapper.selectOne(sessionWrapper);
            
            if (session == null) {
                log.warn("会话不存在或无权删除: sessionId={}, userId={}", sessionId, userId);
                return false;
            }
            
            // 查找该会话的所有消息
            LambdaQueryWrapper<ChatMessage> messageWrapper = new LambdaQueryWrapper<>();
            messageWrapper.eq(ChatMessage::getConversationId, session.getId());
            List<ChatMessage> messages = chatMessageMapper.selectList(messageWrapper);
            
            // 收集所有消息ID
            List<Long> messageIds = new ArrayList<>();
            for (ChatMessage message : messages) {
                messageIds.add(message.getId());
            }
            
            // 删除所有引用
            if (!messageIds.isEmpty()) {
                LambdaQueryWrapper<ChatReference> referenceWrapper = new LambdaQueryWrapper<>();
                referenceWrapper.in(ChatReference::getMessageId, messageIds);
                chatReferenceMapper.delete(referenceWrapper);
            }
            
            // 删除所有消息
            if (!messages.isEmpty()) {
                chatMessageMapper.delete(messageWrapper);
            }
            
            // 删除会话
            chatSessionMapper.delete(sessionWrapper);
            
            log.info("删除会话成功: sessionId={}, userId={}", sessionId, userId);
            return true;
        } catch (Exception e) {
            log.error("删除会话失败: sessionId={}, userId={}", sessionId, userId, e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteSessions(List<String> sessionIds, Long userId) {
        try {
            for (String sessionId : sessionIds) {
                boolean success = deleteSession(sessionId, userId);
                if (!success) {
                    log.warn("批量删除会话失败: sessionId={}", sessionId);
                    // 继续删除其他会话，不中断整个操作
                }
            }
            log.info("批量删除会话完成: count={}, userId={}", sessionIds.size(), userId);
            return true;
        } catch (Exception e) {
            log.error("批量删除会话失败: userId={}", userId, e);
            return false;
        }
    }

    private String generateSessionId() {
        return "sess_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
    }
}