package com.gxwebsoft.ai.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.ai.constants.AuditContent7Constants;
import com.gxwebsoft.ai.service.AuditContent7InvestmentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import cn.hutool.core.util.StrUtil;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AuditContent7InvestmentServiceImpl extends AbstractAuditContentService implements AuditContent7InvestmentService {

    // Dify工作流配置
    private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-rNhgcQkNr2JJP9lePT3ICzgW";
    
    // 审计类别顺序
    private static final List<String> CATEGORY_ORDER = AuditContent7Constants.getAllCategories();

    @Override
    public JSONObject generateInvestmentSituationTableData(String kbIds, String libraryKbIds, 
                                                          String projectLibrary, String userName, 
                                                          String history, String suggestion) {
        log.info("开始生成重大投资情况审计表数据 - 用户: {}, kbIds: {}, libraryIds: {}, projectLibrary: {}", 
                userName, kbIds, libraryKbIds, projectLibrary);
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 异步并行处理每个审计类别
            Map<String, CompletableFuture<JSONArray>> futures = processCategoriesAsync(
                CATEGORY_ORDER, 
                category -> generateCategoryDataAsync(category, kbIds, libraryKbIds, projectLibrary, userName, history, suggestion)
            );
            
            // 等待所有异步任务完成
            CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])).join();
            
            // 合并所有分类的结果
            JSONArray allData = mergeCategoryResults(CATEGORY_ORDER, futures);
            
            log.info("重大投资情况审计表生成成功 - 记录数: {}, 处理时间: {}ms", allData.size(), (System.currentTimeMillis() - startTime));
            
            return buildSuccessResponse(allData, startTime, "investment_situation_audit");
            
        } catch (Exception e) {
            log.error("生成重大投资情况审计表失败", e);
            return buildErrorResponse("生成重大投资情况审计表失败: " + e.getMessage());
        }
    }

    /**
     * 异步生成单个审计类别的数据
     */
    @Async
    public CompletableFuture<JSONArray> generateCategoryDataAsync(String category, String kbIds, 
                                                                 String libraryKbIds, String projectLibrary, 
                                                                 String userName, String history, String suggestion) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("开始生成审计类别 {} 的数据", category);
                
                // 1. 为当前审计类别召回相关知识
                Map<String, List<String>> knowledgeSources = retrieveKnowledgeForCategory(
                    category, kbIds, libraryKbIds, projectLibrary
                );
                
                // 2. 构建完整的知识上下文
                String knowledgeContext = buildCompleteKnowledgeContext(
                    category, knowledgeSources, history, suggestion
                );
                
                // 3. 调用Dify工作流生成数据
                JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName);
                JSONArray categoryData = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, requestBody, "重大投资情况-" + category);
                
                log.info("审计类别 {} 数据生成完成，生成 {} 条记录", category, categoryData.size());
                return categoryData;
                
            } catch (Exception e) {
                log.error("生成审计类别 {} 数据失败", category, e);
                return new JSONArray();
            }
        });
    }

    /**
     * 为单个审计类别检索相关知识
     */
    private Map<String, List<String>> retrieveKnowledgeForCategory(String category, String kbIds, 
                                                                 String libraryKbIds, String projectLibrary) {
        Map<String, List<String>> knowledgeSources = new HashMap<>();
        knowledgeSources.put("enterprise", new ArrayList<>());
        knowledgeSources.put("regulation", new ArrayList<>());
        knowledgeSources.put("auditCase", new ArrayList<>());
        knowledgeSources.put("financial", new ArrayList<>()); // 财务数据单独处理
        
        // 构建当前审计类别的查询词
        List<String> categoryQueries = buildCategoryQueries(category);
        
        // 企业单位库检索
        if (StrUtil.isNotBlank(kbIds)) {
            Arrays.stream(kbIds.split(","))
                .map(String::trim)
                .filter(StrUtil::isNotBlank)
                .forEach(kbId -> {
                    knowledgeSources.get("enterprise")
                        .addAll(queryKnowledgeBase(kbId, categoryQueries, 120));
                    // 单独查询财务相关文档
                    knowledgeSources.get("financial")
                        .addAll(queryKnowledgeBase(kbId, 
                            Arrays.asList("资产负债表", "利润表", "现金流量表", "会计科目", "银行流水"), 80));
                });
        }
        
        // 公共法律法规库检索
        if (StrUtil.isNotBlank(libraryKbIds)) {
            Arrays.stream(libraryKbIds.split(","))
                .map(String::trim)
                .filter(StrUtil::isNotBlank)
                .forEach(libId -> knowledgeSources.get("regulation")
                    .addAll(queryKnowledgeBase(libId, categoryQueries, 100)));
        }
        
        // 审计案例库检索
        if (StrUtil.isNotBlank(projectLibrary)) {
            knowledgeSources.get("auditCase").addAll(
                queryKnowledgeBase(projectLibrary, categoryQueries, 80));
        }
        
        // 智能去重和排序（按相关性）
        knowledgeSources.forEach((key, list) -> {
            List<String> processed = list.stream()
                    .distinct()
                    .sorted(this::investmentRelevanceComparator)
                    .limit(getLimitBySourceType(key))
                    .collect(Collectors.toList());
            knowledgeSources.put(key, processed);
        });
        
        log.debug("审计类别 {} 知识检索完成 - 企业: {}条, 法规: {}条, 案例: {}条, 财务: {}条", 
                 category, 
                 knowledgeSources.get("enterprise").size(),
                 knowledgeSources.get("regulation").size(),
                 knowledgeSources.get("auditCase").size(),
                 knowledgeSources.get("financial").size());
        
        return knowledgeSources;
    }

    /**
     * 构建审计类别特定的查询词
     */
    private List<String> buildCategoryQueries(String category) {
        switch (category) {
            case AuditContent7Constants.CATEGORY_MAJOR_INVESTMENT:
                return Arrays.asList("对外投资 决策程序 审批手续 可行性研究 投资效益", 
                                   "长期投资 短期投资 投资合同 投资回报");
            case AuditContent7Constants.CATEGORY_MAJOR_PROJECT:
                return Arrays.asList("工程建设 项目审批 安全质量 环保要求 工程效益", 
                                   "工程项目 工程管理 竣工验收");
            case AuditContent7Constants.CATEGORY_MAJOR_CAPITAL:
                return Arrays.asList("资本运作 并购重组 交易对价 资金来源", 
                                   "股权交易 资产评估 资本运营");
            case AuditContent7Constants.CATEGORY_MAJOR_ASSET_DISPOSAL:
                return Arrays.asList("资产处置 资产评估 交易价格 产权交易", 
                                   "资产转让 资产拍卖 资产划转");
            case AuditContent7Constants.CATEGORY_MAJOR_PROCUREMENT:
                return Arrays.asList("物资采购 服务采购 招标投标 采购价格", 
                                   "采购合同 供应商 采购管理");
            case AuditContent7Constants.CATEGORY_MAJOR_GUARANTEE:
                return Arrays.asList("担保借款 担保合同 借款合同 风险控制", 
                                   "对外担保 借款审批 抵押质押");
            default:
                return Arrays.asList(category);
        }
    }

    /**
     * 构建完整的知识上下文
     */
    private String buildCompleteKnowledgeContext(String category, Map<String, List<String>> knowledgeSources, 
                                               String history, String suggestion) {
        StringBuilder context = new StringBuilder();
        
        // 1. 审计要求说明
        context.append("## 重大投资情况审计要求 - ").append(category).append("\n");
        context.append("请基于以下知识生成").append(category).append("相关的审计表格数据：\n\n");
        context.append("**审计目标：**\n");
        context.append("- 核查重大投资决策的合规性和民主性\n");
        context.append("- 检查审批手续的完备性\n");
        context.append("- 评估可行性研究和尽职调查的充分性\n");
        context.append("- 核査投资项目的效益情况\n");
        context.append("- 识别决策程序、审批过程、操作过程中的风险和问题\n\n");
        
        // 2. 审计方法（从常量中获取）
        context.append("## 审计方法及步骤\n");
        context.append(AuditContent7Constants.AUDIT_INSTRUCTIONS.get("GENERAL_RULE")).append("\n\n");
        
        // 3. 审计指令（决策程序检查）
        context.append("## 审计检查指令\n");
        context.append(AuditContent7Constants.AUDIT_INSTRUCTIONS.get("DECISION_SYSTEM_CHECK")).append("\n");
        context.append(AuditContent7Constants.AUDIT_INSTRUCTIONS.get("DECISION_PROCEDURE_CHECK")).append("\n\n");
        
        // 4. 数据格式要求
        context.append("## 数据格式要求\n");
        context.append("需要生成").append(category).append("分类的数据，尽可能生成多个实例：\n");
        context.append("- ").append(category).append("：").append(AuditContent7Constants.CATEGORY_DESCRIPTIONS.get(category)).append("\n");
        context.append("\n");
        
        context.append("每条记录应包含5个核心字段：\n");
        context.append("- **category**：固定为\"").append(category).append("\"\n");
        context.append("- **auditContent**：具体的审计内容，从以下模板中选择或根据知识库生成\n");
        context.append("- **checkEvidence**：详细的检查证据描述，必须包含：\n");
        context.append("  ①查阅的具体文件名称和内容\n");
        context.append("  ②检查过程和方法\n");
        context.append("  ③与制度要求的差异点\n");
        context.append("  ④明确的总结性结论（问题、风险、合规状况）\n");
        context.append("- **testResult**：测试结果（通过/不通过/待检查），严格判断：\n");
        context.append("  • 通过：证据充分且完全符合要求\n");
        context.append("  • 不通过：制度不一致、执行不到位、证据不充分\n");
        context.append("  • 待检查：无法确定，需要进一步检查\n");
//        context.append("- **workPaperIndex**：相关《工作底稿索引FileId》，必须是实际存在的完整文件FileId，确保能在文件夹中搜索到\n");
        context.append("- **workPaperIndex**：相关[\"实际存在的完整文件名||FileUrl\"]，必须是实际存在的完整文件名，不能使用附表标题，确保能在文件夹中搜索到\n");
        context.append("- **fileIndex**：相关《文件索引》，关联的支持文件\n\n");
        
        // 5. 审计内容模板（提供参考）
        context.append("## 审计内容模板（供参考）\n");
        List<String> templates = AuditContent7Constants.AUDIT_CONTENT_TEMPLATES.get(category);
        if (templates != null && !templates.isEmpty()) {
            for (int i = 0; i < Math.min(templates.size(), 5); i++) {
                context.append(i + 1).append(". ").append(templates.get(i)).append("\n");
            }
        }
        context.append("（请根据知识库内容，从不同角度生成多个审计检查点）\n\n");
        
        // 6. 文件类型参考（用于工作底稿索引）
        context.append("## 相关文件类型参考\n");
        AuditContent7Constants.FILE_TYPE_KEYWORDS.forEach((type, keywords) -> {
            context.append("- ").append(type).append("：").append(String.join("、", keywords)).append("\n");
        });
        context.append("\n");
        
        // 7. 历史内容
        if (StrUtil.isNotBlank(history)) {
            context.append("## 历史生成内容\n");
            context.append("以下是之前生成的内容，请基于此进行优化：\n");
            context.append(history).append("\n\n");
        }
        
        // 8. 用户建议
        if (StrUtil.isNotBlank(suggestion)) {
            context.append("## 用户优化建议\n");
            context.append("请根据以下建议对生成内容进行调整：\n");
            context.append(suggestion).append("\n\n");
        }
        
        // 9. 企业单位知识
        if (!knowledgeSources.get("enterprise").isEmpty()) {
            context.append("## 企业单位制度知识\n");
            knowledgeSources.get("enterprise").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
            context.append("\n");
        }
        
        // 10. 法律法规知识
        if (!knowledgeSources.get("regulation").isEmpty()) {
            context.append("## 法律法规知识\n");
            knowledgeSources.get("regulation").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
            context.append("\n");
        }
        
        // 11. 审计案例知识
        if (!knowledgeSources.get("auditCase").isEmpty()) {
            context.append("## 审计案例知识\n");
            knowledgeSources.get("auditCase").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
            context.append("\n");
        }
        
        // 12. 财务数据知识
        if (!knowledgeSources.get("financial").isEmpty()) {
            context.append("## 财务数据知识\n");
            context.append("（重点关注：资产负债表、利润表、会计科目、银行流水等）\n");
            knowledgeSources.get("financial").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
        }

        context.append("## 特别提醒\n");
        context.append("1. 除了本次说明中提供的数据知识等依据，不能从其他地方读取数据，不能凭空捏造数据\n");
        return context.toString();
    }

    /**
     * 重大投资情况相关性比较器
     */
    private int investmentRelevanceComparator(String reg1, String reg2) {
        int score1 = calculateInvestmentRelevanceScore(reg1);
        int score2 = calculateInvestmentRelevanceScore(reg2);
        return Integer.compare(score2, score1); // 降序排列
    }

    /**
     * 计算重大投资情况相关性分数
     */
    private int calculateInvestmentRelevanceScore(String content) {
        return AuditContent7Constants.KEYWORD_WEIGHTS.entrySet().stream()
                .filter(entry -> content.contains(entry.getKey()))
                .mapToInt(Map.Entry::getValue)
                .sum();
    }

    /**
     * 根据知识来源类型获取限制数量
     */
    private int getLimitBySourceType(String sourceType) {
        switch (sourceType) {
            case "enterprise": return 120;
            case "regulation": return 100;
            case "auditCase": return 80;
            case "financial": return 60;
            default: return 50;
        }
    }
    
    /**
     * 重写callWorkflow方法，适配重大投资情况工作流的返回格式
     */
    @Override
    protected JSONArray callWorkflow(String url, String token, JSONObject requestBody, String workflowName) {
        try {
            log.info("调用{}工作流，请求体长度: {}", workflowName, requestBody.toString().length());
            
            // 调用父类方法获取工作流响应
            JSONArray result = super.callWorkflow(url, token, requestBody, workflowName);
            
            // 如果父类方法返回结果为空，则尝试按重大投资情况特有的格式解析
            if (result == null || result.isEmpty()) {
                // 这里可以根据需要添加特定的解析逻辑
                log.warn("{}工作流返回结果为空，使用默认空数组", workflowName);
                return new JSONArray();
            }
            
            log.info("成功获取{}工作流返回数据，记录数: {}", workflowName, result.size());
            return result;
            
        } catch (Exception e) {
            log.error("调用{}工作流失败", workflowName, e);
            throw new RuntimeException("调用" + workflowName + "工作流失败: " + e.getMessage(), e);
        }
    }
    
}