/**
 * @ProjectName: 智慧评标-主观分助手
 * @Package: com.zhpb.gdyd_zhpb_zgf.service
 * @ClassName: ComparisonAsyncService
 * @Description: 供应商对比分析异步处理服务
 * @Author: 张志锋
 * @Date: 2025-12-02
 * @Version: 1.0
 * @Copyright: © 2025 智慧评标-主观分助手
 */
package com.zhpb.gdyd_zhpb_zgf.service;

import com.alibaba.fastjson2.JSON;
import com.zhpb.gdyd_zhpb_zgf.context.ModelRequestContextHolder;
import com.zhpb.gdyd_zhpb_zgf.dto.ComparisonRequest;
import com.zhpb.gdyd_zhpb_zgf.dto.ComparisonResponse;
import com.zhpb.gdyd_zhpb_zgf.entity.mysql.ComparisonTask;
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.pgsql.PdfVector;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.ComparisonTaskRepository;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.FileRepository;
import com.zhpb.gdyd_zhpb_zgf.repository.pgsql.PdfVectorRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 供应商对比分析异步处理服务
 * 专门处理耗时的异步任务，避免阻塞主线程
 */
@Service
public class ComparisonAsyncService {

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

    @Autowired
    private ComparisonTaskRepository comparisonTaskRepository;

    @Autowired
    private FileRepository fileRepository;

    @Autowired
    private PromptTemplateService promptTemplateService;

    @Autowired
    private AIModelService aiModelService;

    @Autowired
    private com.zhpb.gdyd_zhpb_zgf.repository.mysql.SupplierRepository supplierRepository;

    @Autowired
    private PdfVectorRepository pdfVectorRepository;

    @Autowired
    private PdfContentCache pdfContentCache;

    @Autowired
    private FilePathResolver filePathResolver;

    // 专用线程池用于并行处理维度和供应商对比
    private final java.util.concurrent.ExecutorService comparisonExecutor = 
        java.util.concurrent.Executors.newFixedThreadPool(
            Math.max(4, Runtime.getRuntime().availableProcessors() * 2),
            new java.util.concurrent.ThreadFactory() {
                private final java.util.concurrent.atomic.AtomicInteger counter = new java.util.concurrent.atomic.AtomicInteger(0);
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r, "comp-parallel-" + counter.incrementAndGet());
                    t.setDaemon(true);
                    return t;
                }
            });

    /**
     * 异步处理供应商对比分析任务
     * @param taskId 任务ID
     */
    @Async("comparisonTaskExecutor")
    public void processComparisonAsync(String taskId) {
        long startTime = System.currentTimeMillis();
        logger.info("[横向对比] ========== 开始供应商对比分析任务: taskId={} ==========", taskId);

        try {
            ComparisonTask task = comparisonTaskRepository.findByTaskId(taskId);
            if (task == null) {
                logger.error("[横向对比] 对比任务不存在: {}", taskId);
                return;
            }

            // 更新任务状态为处理中
            task.setStatus("processing");
            task.setProgress(10);
            comparisonTaskRepository.save(task);
            logger.info("[横向对比] 步骤1: 任务状态已更新为processing");

            // 解析供应商ID和维度
            List<String> vendorIds = JSON.parseArray(task.getVendorIds(), String.class);
            List<ComparisonRequest.ComparisonDimension> dimensions =
                JSON.parseArray(task.getDimensions(), ComparisonRequest.ComparisonDimension.class);

            logger.info("[横向对比] 步骤2: 解析任务参数 - 供应商数量={}, 维度数量={}", vendorIds.size(), dimensions.size());
            for (int i = 0; i < vendorIds.size(); i++) {
                logger.info("[横向对比]   供应商{}: {}", i + 1, vendorIds.get(i));
            }
            for (int i = 0; i < dimensions.size(); i++) {
                logger.info("[横向对比]   维度{}: {}", i + 1, dimensions.get(i).getValue());
            }

            // 构建对比结果矩阵 - 维度+供应商双层并行处理
            final String projectId = task.getProjectId();
            final int totalDimensions = dimensions.size();
            final int totalVendors = vendorIds.size();
            final java.util.concurrent.atomic.AtomicInteger completedDimensions = new java.util.concurrent.atomic.AtomicInteger(0);
            
            logger.info("[横向对比] 步骤3: 开始并行处理 {} 个维度", totalDimensions);
            
            // 并行处理所有维度
            List<CompletableFuture<ComparisonResponse.ResultMatrixItem>> dimensionFutures = 
                dimensions.stream()
                    .map(dimension -> CompletableFuture.supplyAsync(() -> {
                        long dimStartTime = System.currentTimeMillis();
                        ComparisonResponse.ResultMatrixItem matrixItem = new ComparisonResponse.ResultMatrixItem();
                        matrixItem.setDimension(dimension.getValue());
                        matrixItem.setDimensionType(dimension.getType());

                        logger.info("[横向对比] >>> 开始处理维度: '{}'", dimension.getValue());
                        
                        // 嵌套并行：每个维度内部再并行处理所有供应商
                        List<CompletableFuture<ComparisonResponse.VendorComparison>> vendorFutures = 
                            vendorIds.stream()
                                .map(vendorId -> CompletableFuture.supplyAsync(() -> 
                                    generateVendorComparison(projectId, vendorId, dimension), comparisonExecutor))
                                .collect(Collectors.toList());
                        
                        // 等待该维度下所有供应商分析完成
                        List<ComparisonResponse.VendorComparison> comparisons = vendorFutures.stream()
                            .map(CompletableFuture::join)
                            .collect(Collectors.toList());

                        matrixItem.setComparisons(comparisons);
                        int completed = completedDimensions.incrementAndGet();
                        long dimDuration = System.currentTimeMillis() - dimStartTime;
                        logger.info("[横向对比] <<< 维度 '{}' 分析完成 ({}/{})，耗时: {}ms", 
                            dimension.getValue(), completed, totalDimensions, dimDuration);
                        return matrixItem;
                    }, comparisonExecutor))
                    .collect(Collectors.toList());
            
            // 更新进度为50%表示并行处理已启动
            task.setProgress(50);
            comparisonTaskRepository.save(task);
            
            // 等待所有维度分析完成并汇总结果
            List<ComparisonResponse.ResultMatrixItem> resultMatrix = dimensionFutures.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
            
            logger.info("[横向对比] 步骤4: 所有 {} 个维度分析完成，开始保存结果", totalDimensions);

            // 保存结果并更新任务状态
            task.setResult(JSON.toJSONString(resultMatrix));
            task.setStatus("completed");
            task.setProgress(100);
            task.setCompletedTime(LocalDateTime.now());
            comparisonTaskRepository.save(task);

            long totalDuration = System.currentTimeMillis() - startTime;
            logger.info("[横向对比] ========== 任务完成: taskId={}, 维度数={}, 供应商数={}, 总耗时={}ms ({}秒) ==========", 
                taskId, totalDimensions, totalVendors, totalDuration, String.format("%.1f", totalDuration / 1000.0));

        } catch (Exception e) {
            logger.error("供应商对比分析失败: taskId={}", taskId, e);

            // 更新任务状态为失败
            try {
                ComparisonTask task = comparisonTaskRepository.findByTaskId(taskId);
                if (task != null) {
                    task.setStatus("failed");
                    task.setErrorMessage(e.getMessage());
                    comparisonTaskRepository.save(task);
                }
            } catch (Exception ex) {
                logger.error("更新任务失败状态时出错", ex);
            }
        }
    }

    /**
     * 生成供应商对比分析
     */
    private ComparisonResponse.VendorComparison generateVendorComparison(String projectId, String vendorId,
                                                                       ComparisonRequest.ComparisonDimension dimension) {
        long vendorStartTime = System.currentTimeMillis();
        String vendorName = extractSupplierNameFromVendorId(vendorId);
        logger.info("[横向对比]   -> 开始分析供应商: {} ({}), 维度: {}", vendorName, vendorId, dimension.getValue());
        
        ComparisonResponse.VendorComparison comparison = new ComparisonResponse.VendorComparison();
        comparison.setVendorId(vendorId);
        comparison.setVendorName(vendorName);

        try {
            // 获取供应商的文件信息
            List<File> vendorFiles = fileRepository.findByProjectIdAndSupplierId(projectId, vendorId);
            logger.info("[横向对比]      获取到 {} 个文件", vendorFiles.size());

            // 获取对比提示词模板
            PromptTemplate template = promptTemplateService.getActiveTemplate("comparison");
            String promptTemplate = template != null ? template.getPromptContent() :
                "请对供应商在{dimension}维度的表现进行分析。\n\n供应商文件：{files}\n\n请直接返回分析结果。";

            // 构建供应商信息（包含实际文件内容）
            StringBuilder supplierInfo = new StringBuilder();
            supplierInfo.append("供应商名称: ").append(vendorName).append("\n");
            supplierInfo.append("供应商ID: ").append(vendorId).append("\n");
            supplierInfo.append("文件数量: ").append(vendorFiles.size()).append("\n\n");

            // 每个文件内容的最大长度限制（避免超出token限制）
            final int MAX_CONTENT_LENGTH_PER_FILE = 5000;
            // 所有文件内容的总长度限制
            final int MAX_TOTAL_CONTENT_LENGTH = 30000;
            int totalContentLength = 0;

            for (File file : vendorFiles) {
                supplierInfo.append("## 文件: ").append(file.getFileName()).append("\n");
                
                // 获取文件实际内容
                String content = getFileContent(file);
                if (content != null && !content.trim().isEmpty()) {
                    // 截取内容以控制长度
                    if (content.length() > MAX_CONTENT_LENGTH_PER_FILE) {
                        content = content.substring(0, MAX_CONTENT_LENGTH_PER_FILE) + "...(内容已截断)";
                    }
                    // 检查总长度限制
                    if (totalContentLength + content.length() > MAX_TOTAL_CONTENT_LENGTH) {
                        supplierInfo.append("(已达到内容长度限制，跳过后续文件内容)\n\n");
                        break;
                    }
                    supplierInfo.append("内容摘要:\n").append(content).append("\n\n");
                    totalContentLength += content.length();
                    logger.debug("[横向对比]      文件 {} 内容长度: {} 字符", file.getFileName(), content.length());
                } else {
                    supplierInfo.append("(无法提取内容)\n\n");
                    logger.warn("[横向对比]      文件 {} 无法提取内容", file.getFileName());
                }
            }
            
            logger.info("[横向对比]      供应商 {} 文件内容总长度: {} 字符", vendorName, totalContentLength);

            // 替换模板变量
            String prompt = promptTemplate
                .replace("{comparison_dimension}", dimension.getValue())
                .replace("{supplier_info}", supplierInfo.toString());
            
            // 强制要求纯文本格式
            prompt += "\n\n请注意：请仅返回纯文本格式，不要使用Markdown、HTML或其他标记语言（如 **加粗**、# 标题等）。";

            // 调用AI生成分析结果
            String analysis = callDeepSeekForComparison(prompt);

            comparison.setSummary(analysis);
            comparison.setSimilarityScores(Arrays.asList(0.8, 0.7, 0.9)); // 模拟相似度分数

            // 设置文件信息
            List<ComparisonResponse.FileInfo> fileInfos = vendorFiles.stream()
                .map(this::convertToFileInfo)
                .collect(Collectors.toList());
            comparison.setFileInfo(fileInfos);

            long vendorDuration = System.currentTimeMillis() - vendorStartTime;
            logger.info("[横向对比]   <- 供应商 {} 分析完成，耗时: {}ms", vendorName, vendorDuration);

        } catch (Exception e) {
            logger.error("[横向对比] 生成供应商对比分析失败: vendorId={}, error={}", vendorId, e.getMessage(), e);
            comparison.setSummary("分析失败: " + e.getMessage());
            comparison.setSimilarityScores(new ArrayList<>());
            comparison.setFileInfo(new ArrayList<>());
        }

        return comparison;
    }

    /**
     * 转换文件信息
     */
    private ComparisonResponse.FileInfo convertToFileInfo(File file) {
        ComparisonResponse.FileInfo fileInfo = new ComparisonResponse.FileInfo();
        fileInfo.setFileId(file.getFileId());
        fileInfo.setFileName(file.getFileName());
        fileInfo.setFileType(getFileTypeName(file.getFileTypeId()));
        fileInfo.setFileSize(file.getFileSize());
        return fileInfo;
    }

    /**
     * 获取文件类型名称
     */
    private String getFileTypeName(Long fileTypeId) {
        if (fileTypeId != null) {
            switch (fileTypeId.intValue()) {
                case 5: return "技术文件";
                case 6: return "商务文件";
                case 7: return "报价文件";
                default: return "其他文件";
            }
        }
        return "未知类型";
    }

    /**
     * 从供应商ID推断供应商名称
     */
    private String extractSupplierNameFromVendorId(String vendorId) {
        try {
            com.zhpb.gdyd_zhpb_zgf.entity.mysql.Supplier supplier = supplierRepository.findBySupplierId(vendorId);
            if (supplier != null && supplier.getSupplierName() != null) {
                return supplier.getSupplierName();
            }
        } catch (Exception e) {
            logger.warn("查询供应商名称失败: vendorId={}", vendorId);
        }
        return vendorId;
    }

    /**
     * 调用DeepSeek进行供应商对比分析（带详细日志）
     */
    private String callDeepSeekForComparison(String prompt) {
        long apiStartTime = System.currentTimeMillis();
        String threadName = Thread.currentThread().getName();
        
        // 记录请求开始时间和参数摘要
        logger.info("[AI调用] ========== 开始 [{}] ==========", threadName);
        logger.info("[AI调用] 请求时间: {}", java.time.LocalDateTime.now());
        logger.info("[AI调用] 提示词长度: {} 字符", prompt.length());
        // 打印提示词前200字符作为摘要
        String promptSummary = prompt.length() > 200 ? prompt.substring(0, 200) + "..." : prompt;
        logger.debug("[AI调用] 提示词摘要: {}", promptSummary);
        
        try {
            ModelRequestContextHolder.setRequestSource("COMPARISON_ANALYSIS");
            String result;
            try {
                result = aiModelService.generateResponse("", prompt);
            } finally {
                ModelRequestContextHolder.clear();
            }

            long apiDuration = System.currentTimeMillis() - apiStartTime;
            
            if (result != null && !result.trim().isEmpty()) {
                logger.info("[AI调用] 返回成功 [{}] - 返回长度: {} 字符, 耗时: {}ms ({:.1f}秒)", 
                    threadName, result.length(), apiDuration, apiDuration / 1000.0);
                // 打印返回值前100字符作为摘要
                String resultSummary = result.length() > 100 ? result.substring(0, 100) + "..." : result;
                logger.debug("[AI调用] 返回摘要: {}", resultSummary);
                logger.info("[AI调用] ========== 完成 [{}] 耗时: {}ms ==========", threadName, apiDuration);
                return result.trim();
            }

            logger.warn("[AI调用] 返回为空 [{}] - 耗时: {}ms", threadName, apiDuration);
            return "AI分析结果暂不可用";

        } catch (Exception e) {
            long apiDuration = System.currentTimeMillis() - apiStartTime;
            logger.error("[AI调用] 调用失败 [{}] - 错误: {}, 耗时: {}ms", threadName, e.getMessage(), apiDuration, e);
            return "AI分析失败: " + e.getMessage();
        }
    }

    /**
     * 获取文件实际内容
     * 优先从向量库获取，如无则从原文件读取
     *
     * @param file 文件实体
     * @return 文件内容，如果无法获取则返回空字符串
     */
    private String getFileContent(File file) {
        if (file == null || file.getFileId() == null) {
            return "";
        }

        try {
            // 1. 首先尝试从向量库获取内容
            List<PdfVector> vectors = pdfVectorRepository.findByFileId(file.getFileId());
            if (vectors != null && !vectors.isEmpty()) {
                // 合并所有向量块的内容
                String content = vectors.stream()
                    .map(PdfVector::getContent)
                    .filter(Objects::nonNull)
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .collect(Collectors.joining("\n\n"));
                
                if (!content.isEmpty()) {
                    logger.debug("[横向对比] 从向量库获取文件内容: fileId={}, 内容长度={}", 
                        file.getFileId(), content.length());
                    return content;
                }
            }

            // 2. 向量库没有内容，降级从原文件读取
            logger.debug("[横向对比] 向量库无内容，尝试从原文件读取: fileId={}", file.getFileId());
            
            // 解析文件路径
            Optional<Path> resolvedPath = filePathResolver.resolveExistingPath(
                file.getFilePath(), file.getProjectId(), file.getFileName());
            
            if (resolvedPath.isEmpty()) {
                logger.warn("[横向对比] 无法解析文件路径: fileId={}, filePath={}", 
                    file.getFileId(), file.getFilePath());
                return "";
            }

            // 使用 PdfContentCache 读取内容（带缓存，最多读取50页）
            String pdfPath = resolvedPath.get().toString();
            String content = pdfContentCache.getFullContent(pdfPath, 50);
            
            if (content != null && !content.isEmpty()) {
                logger.debug("[横向对比] 从原文件读取内容: fileId={}, 内容长度={}", 
                    file.getFileId(), content.length());
                return content;
            }

            return "";

        } catch (Exception e) {
            logger.error("[横向对比] 获取文件内容失败: fileId={}, error={}", 
                file.getFileId(), e.getMessage(), e);
            return "";
        }
    }
}
