package top.tqx.demo_1.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import top.tqx.demo_1.dto.ExamGenerateRequest;
import top.tqx.demo_1.dto.ExamGenerateResponse;
import top.tqx.demo_1.entity.File;
import top.tqx.demo_1.enums.FileProcessStepStatus;
import top.tqx.demo_1.mapper.FileMapper;

import java.time.LocalDateTime;

@Slf4j
@Service
public class AsyncExamService {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private ExamService examService;

    @Autowired
    private FileMapper fileMapper;

    public static final String EXAM_STATUS_UNGENERATED = "UNGENERATED";
    public static final String EXAM_STATUS_GENERATING = "GENERATING";
    public static final String EXAM_STATUS_GENERATED = "GENERATED";
    public static final String EXAM_STATUS_FAILED = "FAILED";

    @Async("examTaskExecutor")
    public void generateQuestionsAsync(ExamGenerateRequest request) {
        log.info("========== 异步任务开始执行 ==========");
        log.info("requestId={}, filePath={}, fileId={}, 当前线程: {}", 
                request.getRequestId(), request.getFilePath(), request.getFileId(), Thread.currentThread().getName());
        
        String filePath = request.getFilePath();
        Long fileId = null;
        String errorMessage = null;
        
        try {
            log.info("步骤1: 查找文件ID");
            
            // 优先使用 request 中的 fileId（来自 collection_file）
            if (request.getFileId() != null) {
                log.info("优先使用 request 中的 fileId: {}", request.getFileId());
                fileId = request.getFileId();
            }
            
            // 如果没有 request 中的 fileId，尝试通过路径查询
            if (fileId == null && filePath != null && !filePath.isEmpty()) {
                fileId = findFileIdByPath(filePath, null);
                log.info("通过路径查询得到 fileId: {}", fileId);
            }
            
            log.info("最终确定的 fileId: {}", fileId);
            
            // 步骤2: 更新状态为 GENERATING（只要有 fileId 就更新）
            if (fileId != null) {
                log.info("步骤2: 更新状态为 GENERATING");
                updateFileExamStatus(fileId, EXAM_STATUS_GENERATING, "正在生成题目，请稍后...");
            }
            
            log.info("步骤3: 调用 generateQuestions");
            ExamGenerateResponse response = examService.generateQuestions(request);
            log.info("步骤3完成: total={}", response.getTotal());
            
            // 步骤4: 更新状态为完成
            if (fileId != null) {
                log.info("步骤4: 更新状态为 GENERATED");
                if (response.getTotal() == null || response.getTotal() == 0) {
                    log.warn("RAG服务返回0道题目，记录警告信息");
                    updateFileExamStatus(fileId, EXAM_STATUS_GENERATED, "警告：未生成任何题目。可能原因：文档内容为空、文档内容无法提取题目、或文档格式不支持。source_chunks_used=" + response.getSourceChunksUsed());
                } else {
                    String processMessage = "生成成功，共" + response.getTotal() + "道题";
                    log.info("response.getAiAnalysis() = {}", response.getAiAnalysis());
                    log.info("response.getAiAnalysis() == null? {}", response.getAiAnalysis() == null);
                    if (response.getAiAnalysis() != null) {
                        try {
                            String aiAnalysisJson = objectMapper.writeValueAsString(response.getAiAnalysis());
                            log.info("序列化成功的 aiAnalysisJson = {}", aiAnalysisJson);
                            processMessage += "\n\n【AI分析结果】\n" + aiAnalysisJson;
                        } catch (Exception e) {
                            log.warn("序列化 aiAnalysis 失败: {}", e.getMessage(), e);
                            String aiAnalysisString = response.getAiAnalysis().toString();
                            log.info("使用 toString(): {}", aiAnalysisString);
                            processMessage += "\n\n【AI分析结果】" + aiAnalysisString;
                        }
                    } else {
                        log.warn("response.getAiAnalysis() 为 null，不追加 AI 分析结果");
                    }
                    log.info("最终 processMessage = {}", processMessage);
                    updateFileExamStatus(fileId, EXAM_STATUS_GENERATED, processMessage);
                }
            }
            
            log.info("========== 异步任务成功完成 ==========");
        } catch (Exception e) {
            String errorType = e.getMessage() != null && (e.getMessage().contains("500") || e.getMessage().contains("INTERNAL SERVER ERROR")) 
                ? "[AI端错误]" : "[本地错误]";
            errorMessage = String.format("生成失败%s: %s", errorType, e.getMessage());
            log.error("========== 异步任务执行失败 ==========", e);
            if (fileId != null) {
                updateFileExamStatus(fileId, EXAM_STATUS_FAILED, errorMessage);
            }
            // 不抛出RuntimeException，避免产生"Unexpected exception occurred invoking async method"日志
            log.info("异步任务已优雅结束，文件状态已更新为FAILED");
        }
    }

    private Long findFileIdByPath(String filePath, Long requestFileId) {
        try {
            log.info("开始查询 file 表: filePath={}, requestFileId={}", filePath, requestFileId);
            
            // 优先通过 ID 查询（如果提供了 requestFileId）
            if (requestFileId != null) {
                log.info("尝试通过 ID 查询: fileId={}", requestFileId);
                File fileById = fileMapper.selectById(requestFileId);
                if (fileById != null) {
                    log.info("通过 ID 查询成功: id={}, fileName={}, filePath={}", 
                        fileById.getId(), fileById.getFileName(), fileById.getFilePath());
                    return fileById.getId();
                } else {
                    log.warn("通过 ID 查询失败，尝试通过路径查询");
                }
            }
            
            // 其次通过路径查询
            log.info("尝试通过路径查询: filePath={}", filePath);
            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<File> wrapper = 
                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
            wrapper.eq(File::getFilePath, filePath);
            File file = fileMapper.selectOne(wrapper);
            
            if (file != null) {
                log.info("通过路径查询成功: id={}, fileName={}, filePath={}", 
                    file.getId(), file.getFileName(), file.getFilePath());
                return file.getId();
            } else {
                log.warn("通过路径查询失败: filePath={}", filePath);
                
                // 尝试模糊查询，看看是否有相似的路径
                com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<File> likeWrapper = 
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
                likeWrapper.like(File::getFilePath, "3.docx");
                java.util.List<File> similarFiles = fileMapper.selectList(likeWrapper);
                if (similarFiles != null && !similarFiles.isEmpty()) {
                    log.info("找到 {} 条相似的文件记录:", similarFiles.size());
                    for (File f : similarFiles) {
                        log.info("  - id={}, fileName={}, filePath={}", 
                            f.getId(), f.getFileName(), f.getFilePath());
                    }
                }
                
                return null;
            }
        } catch (Exception e) {
            log.error("查询文件失败: filePath={}, requestFileId={}, error={}", 
                filePath, requestFileId, e.getMessage(), e);
            return null;
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void updateFileExamStatus(Long fileId, String status, String message) {
        if (fileId == null) {
            log.warn("更新文件状态失败: fileId为null");
            return;
        }
        try {
            File file = fileMapper.selectById(fileId);
            if (file != null) {
                log.info("更新文件状态: fileId={}, 从 {} 变为 {}", fileId, file.getExamStatus(), status);
                file.setExamStatus(status);
                if (message != null) {
                    file.setProcessMessage(message);
                }
                
                // 更新流程状态
                if (EXAM_STATUS_GENERATING.equals(status)) {
                    file.setProcessStepStatus(FileProcessStepStatus.EXAM_GENERATING.getCode());
                    file.setProcessStepMessage(FileProcessStepStatus.EXAM_GENERATING.getDescription());
                } else if (EXAM_STATUS_GENERATED.equals(status)) {
                    // 如果向量化已完成且题目生成完成，则标记为全部完成
                    if (FileProcessStepStatus.VECTORIZED.getCode().equals(file.getProcessStepStatus())) {
                        file.setProcessStepStatus(FileProcessStepStatus.COMPLETED.getCode());
                        file.setProcessStepMessage(FileProcessStepStatus.COMPLETED.getDescription());
                    } else {
                        file.setProcessStepStatus(FileProcessStepStatus.EXAM_GENERATED.getCode());
                        file.setProcessStepMessage(FileProcessStepStatus.EXAM_GENERATED.getDescription());
                    }
                } else if (EXAM_STATUS_FAILED.equals(status)) {
                    file.setProcessStepStatus(FileProcessStepStatus.EXAM_GENERATE_FAILED.getCode());
                    String stepMsg = FileProcessStepStatus.EXAM_GENERATE_FAILED.getDescription() + ": " + (message != null ? message : "");
                    file.setProcessStepMessage(stepMsg.length() > 500 ? stepMsg.substring(0, 500) : stepMsg);
                }
                
                file.setUpdateTime(LocalDateTime.now());
                int result = fileMapper.updateById(file);
                if (result > 0) {
                    log.info("文件状态更新成功: fileId={}", fileId);
                } else {
                    log.warn("文件状态更新失败: fileId={}, status={}, 未影响任何行", fileId, status);
                }
            } else {
                log.warn("更新文件状态失败: fileId={} 对应的文件不存在", fileId);
            }
        } catch (Exception e) {
            log.error("更新文件题目状态失败: fileId={}, status={}, error={}", fileId, status, e.getMessage(), e);
            throw new RuntimeException("更新文件状态失败", e);
        }
    }
}
