package com.gxwebsoft.ai.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.ai.constants.AuditContent8InternalControlConstants;
import com.gxwebsoft.ai.service.AuditContent8InternalControlService;
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 AuditContent8InternalControlServiceImpl extends AbstractAuditContentService implements AuditContent8InternalControlService {

    // 工作流配置
    private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-R1GN6zKkrfBYVMtwz8c6pyRM";
    
    // 审计测试方法
    private static final List<String> TEST_METHODS = Arrays.asList(
        "符合性测试", "穿行测试", "抽样测试", "观察询问", "文档查阅"
    );

    @Override
    public JSONObject generateInternalControlTableData(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(
                Arrays.asList(AuditContent8InternalControlConstants.CONTROL_LINKS), 
                controlLink -> generateControlLinkDataAsync(controlLink, kbIds, libraryKbIds, projectLibrary, userName, history, suggestion)
            );
            
            // 等待所有异步任务完成
            CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])).join();
            
            // 合并所有分类的结果
            JSONArray allData = mergeCategoryResults(Arrays.asList(AuditContent8InternalControlConstants.CONTROL_LINKS), futures);
            
            log.info("单位层面财务管理内部控制测试表生成成功 - 记录数: {}, 处理时间: {}ms", allData.size(), (System.currentTimeMillis() - startTime));
            
            return buildSuccessResponse(allData, startTime, "internal_control_audit");
            
        } catch (Exception e) {
            log.error("生成单位层面财务管理内部控制测试表失败", e);
            return buildErrorResponse("生成单位层面财务管理内部控制测试表失败: " + e.getMessage());
        }
    }

    /**
     * 异步生成单个控制环节的数据
     */
    @Async
    public CompletableFuture<JSONArray> generateControlLinkDataAsync(String controlLink, String kbIds, String libraryKbIds, String projectLibrary, String userName, String history, String suggestion) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("开始生成控制环节 {} 的数据", controlLink);
                
                // 1. 为当前控制环节召回相关知识
                Map<String, List<String>> knowledgeSources = retrieveKnowledgeForControlLink(
                    controlLink, kbIds, libraryKbIds, projectLibrary
                );
                
                // 2. 构建完整的知识上下文
                String knowledgeContext = buildCompleteKnowledgeContext(
                    controlLink, knowledgeSources, history, suggestion
                );
                
                // 3. 调用工作流生成数据
                JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName);
                JSONArray controlLinkData = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, requestBody, "内部控制-" + controlLink);
                
                log.info("控制环节 {} 数据生成完成，生成 {} 条记录", controlLink, controlLinkData.size());
                return controlLinkData;
                
            } catch (Exception e) {
                log.error("生成控制环节 {} 数据失败", controlLink, e);
                return new JSONArray();
            }
        });
    }

    /**
     * 为单个控制环节检索相关知识
     */
    private Map<String, List<String>> retrieveKnowledgeForControlLink(String controlLink, 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<>());
        
        // 构建当前控制环节的查询词
        List<String> controlQueries = buildControlLinkQueries(controlLink);
        
        // 企业单位库检索
        if (StrUtil.isNotBlank(kbIds)) {
            Arrays.stream(kbIds.split(","))
                .map(String::trim)
                .filter(StrUtil::isNotBlank)
                .forEach(kbId -> knowledgeSources.get("enterprise")
                    .addAll(queryKnowledgeBase(kbId, controlQueries, 120)));
        }
        
        // 公共法律法规库检索
        if (StrUtil.isNotBlank(libraryKbIds)) {
            Arrays.stream(libraryKbIds.split(","))
                .map(String::trim)
                .filter(StrUtil::isNotBlank)
                .forEach(libId -> knowledgeSources.get("regulation")
                    .addAll(queryKnowledgeBase(libId, controlQueries, 100)));
        }
        
        // 审计案例库检索
        if (StrUtil.isNotBlank(projectLibrary)) {
            knowledgeSources.get("auditCase").addAll(
                queryKnowledgeBase(projectLibrary, controlQueries, 80));
        }
        
        // 智能去重和排序
        knowledgeSources.forEach((key, list) -> {
            List<String> processed = list.stream()
                    .distinct()
                    .sorted(this::internalControlComparator)
                    .limit(getLimitBySourceType(key))
                    .collect(Collectors.toList());
            knowledgeSources.put(key, processed);
        });
        
        log.debug("控制环节 {} 知识检索完成 - 企业: {}条, 法规: {}条, 案例: {}条", 
                 controlLink, 
                 knowledgeSources.get("enterprise").size(),
                 knowledgeSources.get("regulation").size(),
                 knowledgeSources.get("auditCase").size());
        
        return knowledgeSources;
    }

    /**
     * 构建控制环节特定的查询词
     */
    private List<String> buildControlLinkQueries(String controlLink) {
        // 根据控制环节构建相关查询词
        List<String> queries = new ArrayList<>();
        
        // 通用查询词
        queries.add(controlLink);
        queries.add("内部控制 " + controlLink);
        queries.add("财务管理 " + controlLink);
        
        // 根据特定控制环节添加相关关键词
        if (controlLink.contains("岗位")) {
            queries.add("岗位职责 不相容职务分离");
            queries.add("岗位设置 职责划分");
        }
        if (controlLink.contains("授权审批")) {
            queries.add("授权审批流程 审批权限");
            queries.add("财务管理授权");
        }
        if (controlLink.contains("重大事项")) {
            queries.add("重大事项决策 集体决策");
            queries.add("三重一大 财务管理");
        }
        if (controlLink.contains("会计")) {
            queries.add("会计核算 会计档案");
            queries.add("会计凭证 会计账簿");
        }
        if (controlLink.contains("信息系统")) {
            queries.add("财务信息系统 数据备份");
            queries.add("信息安全 用户管理");
        }
        if (controlLink.contains("风险")) {
            queries.add("财务风险管理 风险识别");
            queries.add("风险评估 风险应对");
        }
        if (controlLink.contains("内部审计")) {
            queries.add("内审部门 审计监督");
            queries.add("审计检查 审计报告");
        }
        if (controlLink.contains("反舞弊")) {
            queries.add("财务舞弊 举报投诉");
            queries.add("舞弊防范 举报保护");
        }
        
        return queries;
    }

    /**
     * 构建完整的知识上下文
     */
    private String buildCompleteKnowledgeContext(String controlLink, Map<String, List<String>> knowledgeSources, String history, String suggestion) {
        StringBuilder context = new StringBuilder();
        
        // 1. 单位层面财务管理内部控制测试要求
        context.append("## 单位层面财务管理内部控制测试要求 - ").append(controlLink).append("\n");
        context.append("请基于以下知识生成").append(controlLink).append("相关的单位层面财务管理内部控制测试数据：\n\n");
        context.append("1. 控制环节：").append(controlLink).append("\n");
        context.append("2. 控制要求：").append(AuditContent8InternalControlConstants.CONTROL_REQUIREMENTS.get(controlLink)).append("\n");
        context.append("3. 控制活动描述：").append(AuditContent8InternalControlConstants.CONTROL_ACTIVITIES.get(controlLink)).append("\n");
        context.append("4. 控制职责岗位：").append(AuditContent8InternalControlConstants.CONTROL_POSITIONS.get(controlLink)).append("\n");
        context.append("5. 测试步骤：\n");
        AuditContent8InternalControlConstants.TEST_STEPS.get(controlLink).forEach(step -> 
            context.append("   ").append(step).append("\n"));
        context.append("\n");
        
        context.append("## 审计测试要求\n");
        context.append("1. 基于测试步骤逐项检查，评估内部控制的有效性\n");
        context.append("2. 检查证据必须具体到查阅的文件名称、内容、检查过程和发现的问题\n");
        context.append("3. 测试结果必须基于充分证据严格判断：\n");
        context.append("   - 通过：所有测试步骤均得到有效执行且证据充分\n");
        context.append("   - 不通过：任一测试步骤未执行、执行不到位或证据不足\n");
        context.append("4. 工作底稿索引必须填写实际存在的完整文件名\n");
        context.append("5. 重点关注货币资金管理、财务报销、资产管理、物资采购等关键环节\n\n");
        
        // 2. 数据格式要求
        context.append("## 数据格式要求\n");
        context.append("需要生成").append(controlLink).append("控制环节的内部控制测试数据：\n\n");
        
        context.append("**重要：每个测试步骤必须单独生成一条记录**\n\n");
        
        context.append("每条记录应包含以下字段：\n");
        context.append("- controlLink（控制环节）：固定值，不要修改\n");
        context.append("- controlRequirement（控制要求）：固定值，不要修改\n");
        context.append("- controlActivity（控制活动描述）：固定值，不要修改\n");
        context.append("- controlPosition（控制职责岗位）：固定值，不要修改\n");
        context.append("- testSteps（测试步骤）：**只包含当前步骤内容**，如\"（1）是否有制度规定\"\n");
        context.append("- checkEvidence（检查证据）：针对当前测试步骤的详细检查证据\n");
        context.append("- testResult（测试结果）：基于当前测试步骤的检查证据严格判断，只有证据充分且完全符合要求才能判定为\"通过\"，否则必须判定为\"不通过\"\n");
//        context.append("- workPaperIndex（工作底稿索引FileId）：实际存在的完整文件FileId，确保能在文件夹中搜索到\n\n");
        context.append("- workPaperIndex（工作底稿索引文件名）：实际存在的完整文件名||FileUrl，确保能在文件夹中搜索到\n\n");
        
        context.append("**生成规则：**\n");
        context.append("1. **每个测试步骤单独生成一条完整记录**\n");
        context.append("2. 如果测试步骤中有多个小点（如（1）、（2）、（3）），必须为每个小点生成独立记录\n");
        context.append("3. 每条记录的检查证据必须专门针对该测试步骤\n");
        context.append("4. 每条记录的测试结果必须基于该步骤的检查证据独立判断\n");
        context.append("5. 控制环节、控制要求、控制活动描述、控制职责岗位字段在所有相关记录中保持相同\n\n");
        
        // 3. 审计测试方法参考
        context.append("## 审计测试方法参考\n");
        context.append("审计时可采用的测试方法：\n");
        TEST_METHODS.forEach(method -> context.append("- ").append(method).append("\n"));
        context.append("\n");
        
        // 4. 历史内容
        if (StrUtil.isNotBlank(history)) {
            context.append("## 历史生成内容\n");
            context.append("以下是之前生成的内容，请基于此进行优化：\n");
            context.append(history).append("\n\n");
        }
        
        // 5. 用户建议
        if (StrUtil.isNotBlank(suggestion)) {
            context.append("## 用户优化建议\n");
            context.append("请根据以下建议对生成内容进行调整：\n");
            context.append(suggestion).append("\n\n");
        }
        
        // 6. 企业单位知识
        if (!knowledgeSources.get("enterprise").isEmpty()) {
            context.append("## 企业单位知识\n");
            knowledgeSources.get("enterprise").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
            context.append("\n");
        }
        
        // 7. 法律法规知识
        if (!knowledgeSources.get("regulation").isEmpty()) {
            context.append("## 法律法规知识\n");
            knowledgeSources.get("regulation").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
            context.append("\n");
        }
        
        // 8. 审计案例知识
        if (!knowledgeSources.get("auditCase").isEmpty()) {
            context.append("## 审计案例知识\n");
            knowledgeSources.get("auditCase").forEach(knowledge -> 
                context.append(knowledge).append("\n"));
        }

        context.append("**注意：**\n");
        context.append("1. 检查证据必须详细描述：针对当前测试步骤查阅了哪些制度文件、检查了哪些业务凭证、访谈了哪些人员、发现了什么问题\n");
        context.append("2. 测试结果判定必须严格，对于制度不健全、执行不到位、证据不充分的情况必须判定为\"不通过\"\n");
        context.append("3. 工作底稿索引必须准确对应实际审计工作底稿文件名称，不能使用章节标题\n");
        context.append("4. 审计检查可采用：符合性测试、穿行测试、抽样测试、观察询问、文档查阅等方法\n");
        context.append("5. 重点关注内部控制制度的建立健全性和执行的有效性\n\n");
        context.append("6. 除了本次说明中提供的数据知识等依据，不能从其他地方读取数据，不能凭空捏造数据\n");
        return context.toString();
    }

    /**
     * 内部控制相关性比较器
     */
    private int internalControlComparator(String reg1, String reg2) {
        int score1 = calculateInternalControlRelevanceScore(reg1);
        int score2 = calculateInternalControlRelevanceScore(reg2);
        return Integer.compare(score2, score1);
    }

    /**
     * 计算内部控制相关性分数
     */
    private int calculateInternalControlRelevanceScore(String content) {
        return AuditContent8InternalControlConstants.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;
            default: return 50;
        }
    }
    
}