package com.gxwebsoft.ai.service.impl;

import com.aliyun.bailian20231229.Client;
import com.aliyun.bailian20231229.models.RetrieveResponse;
import com.aliyun.bailian20231229.models.RetrieveResponseBody;
import com.aliyun.bailian20231229.models.RetrieveResponseBody.RetrieveResponseBodyData;
import com.aliyun.bailian20231229.models.RetrieveResponseBody.RetrieveResponseBodyDataNodes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.ai.config.KnowledgeBaseConfig;
import com.gxwebsoft.ai.entity.AiCloudFile;
import com.gxwebsoft.ai.factory.KnowledgeBaseClientFactory;
import com.gxwebsoft.ai.service.AiCloudFileService;
import com.gxwebsoft.ai.util.AiCloudKnowledgeBaseUtil;
import com.gxwebsoft.common.core.context.TenantContext;
import com.gxwebsoft.oa.service.OaCompanyService;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public abstract class AbstractAuditContentService {
    
    @Autowired
    protected KnowledgeBaseClientFactory clientFactory;

    @Autowired
    protected KnowledgeBaseConfig config;
    
    @Autowired
    protected AiCloudFileService aiCloudFileService;
    
    @Autowired
    protected OaCompanyService oaCompanyService;
    
    protected static final String DIFY_WORKFLOW_URL = "http://1.14.159.185:8180/v1/workflows/run";
    
    // 用于同步的锁对象池
    private static final Map<String, Object> kbLocks = new ConcurrentHashMap<>();
    
    // 当前请求的主知识库ID集合（用于判断是否需要按文件过滤）
    private static final ThreadLocal<Set<String>> requestMainKbIds = new ThreadLocal<>();
    // 当前请求需要过滤的文件ID列表
    private static final ThreadLocal<List<String>> requestFileIds = new ThreadLocal<>();
    
    /**
     * 设置当前请求的文件ID过滤条件
     */
    public static void setRequestFileIds(Set<String> mainKbIds, List<String> fileIds) {
        requestMainKbIds.set(mainKbIds);
        requestFileIds.set(fileIds);
    }
    
    /**
     * 清除当前请求的文件ID过滤条件
     */
    public static void clearRequestFileIds() {
        requestMainKbIds.remove();
        requestFileIds.remove();
    }
    
    /**
     * 调用工作流通用方法
     */
    protected JSONArray callWorkflow(String url, String token, JSONObject requestBody, String workflowName) {
        try {
            log.info("调用{}工作流，请求体长度: {}", workflowName, requestBody.toString().length());

            String result = HttpUtil.createPost(url)
                    .header("Authorization", token)
                    .header("Content-Type", "application/json")
                    .body(requestBody.toString())
                    .timeout(10 * 60 * 1000)
                    .execute()
                    .body();

            log.info("{}工作流返回结果长度: {}", workflowName, result.length());

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(result);

            String outputText = rootNode.path("data")
                    .path("outputs")
                    .path("result")
                    .asText();

            if (StrUtil.isBlank(outputText)) {
                log.warn("{}工作流返回 result 为空", workflowName);
                return new JSONArray();
            }

            // ★ NEW：先从 ```json``` 中提取
            String jsonText = extractJsonFromMarkdown(outputText);

            // ★ NEW：兜底提取
            if (StrUtil.isBlank(jsonText)) {
                jsonText = extractFirstJson(outputText);
            }

            if (StrUtil.isBlank(jsonText)) {
                log.error("{} 工作流返回内容无法解析为 JSON，原始内容：{}", workflowName, outputText);
                throw new RuntimeException("Dify 返回内容中未找到有效 JSON");
            }

            JSONArray jsonArray = JSONArray.parseArray(jsonText);

            log.info("成功解析{}工作流返回数据，记录数: {}", workflowName, jsonArray.size());
            return jsonArray;

        } catch (Exception e) {
            log.error("调用{}工作流失败", workflowName, e);
            throw new RuntimeException("调用" + workflowName + "工作流失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从 ```json 代码块中提取 JSON
     */
    private static String extractJsonFromMarkdown(String text) {
        if (StrUtil.isBlank(text)) {
            return null;
        }
        Pattern pattern = Pattern.compile("```json\\s*(.*?)\\s*```", Pattern.DOTALL);
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1).trim();
        }
        return null;
    }

    /**
     * 兜底：从混合文本中提取第一个完整 JSON（{} 或 []）
     */
    private static String extractFirstJson(String text) {
        if (StrUtil.isBlank(text)) return null;

        int start = -1;
        char open = 0, close = 0;

        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c == '{' || c == '[') {
                start = i;
                open = c;
                close = (c == '{') ? '}' : ']';
                break;
            }
        }
        if (start == -1) return null;

        int count = 0;
        for (int i = start; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c == open) count++;
            if (c == close) count--;
            if (count == 0) {
                return text.substring(start, i + 1);
            }
        }
        return null;
    }

    /**
     * 构建工作流请求通用方法
     */
    protected JSONObject buildWorkflowRequest(String knowledge, String userName) {
        return buildWorkflowRequest(knowledge, userName, null);
    }
    
    protected JSONObject buildWorkflowRequest(String knowledge, String userName, Integer timeout) {
        JSONObject requestBody = new JSONObject();
        JSONObject inputs = new JSONObject();
        
        inputs.put("knowledge", knowledge);
        
        requestBody.put("inputs", inputs);
        requestBody.put("response_mode", "blocking");
        requestBody.put("user", userName);
        if (timeout != null) {
            requestBody.put("timeout", timeout);
        }
        
        return requestBody;
    }

    /**
     * 查询知识库通用方法
     */
    protected List<String> queryKnowledgeBase(String kbId, List<String> queries, int topK) {
        // 递归获取所有父级单位的kbId
        Set<String> allKbIds = TenantContext.callIgnoreTenant(() -> oaCompanyService.getAllParentKbIds(kbId));
        
        Object lock = kbLocks.computeIfAbsent(kbId, k -> new Object());
        
        synchronized (lock) {
            try {
                // 获取当前请求的fileIds（仅对主知识库生效）
                List<String> fileIds = null;
                Set<String> mainKbIds = requestMainKbIds.get();
                if (mainKbIds != null && mainKbIds.contains(kbId)) {
                    fileIds = requestFileIds.get();
                }
                
                // 1. 收集所有节点和文档ID（包含所有父级kbId）
                List<RetrieveResponseBodyDataNodes> allNodes = new ArrayList<>();
                for (String currentKbId : allKbIds) {
                    allNodes.addAll(collectKnowledgeNodes(currentKbId, queries, topK, fileIds));
                }
                if (allNodes.isEmpty()) {
                    return new ArrayList<>();
                }
                
                // 2. 批量查询文件URL
                Map<String, String> fileUrlMap = TenantContext.callIgnoreTenant(() -> batchQueryFileUrls(allNodes));
                
                // 3. 处理节点生成结果
                return processNodesToResults(allNodes, fileUrlMap);
                
            } catch (Exception e) {
                log.error("查询知识库失败 - kbId: {}", kbId, e);
                return new ArrayList<>();
            }
        }
    }

    /**
     * 收集知识库节点
     */
    private List<RetrieveResponseBodyDataNodes> collectKnowledgeNodes(String kbId, List<String> queries, int topK, List<String> fileIds) {
        List<RetrieveResponseBodyDataNodes> allNodes = new ArrayList<>();
        String workspaceId = config.getWorkspaceId();
        try {
            Client client = clientFactory.createClient();
            for (String query : queries) {
                try {
                    RetrieveResponse resp;
                    if (fileIds != null && !fileIds.isEmpty()) {
                        // fileId格式 file_xxxx_yyyy，知识库tag保存的是xxxx部分
                        List<String> tags = fileIds.stream()
                            .map(id -> StrUtil.subBetween(id, "_", "_"))
                            .filter(StrUtil::isNotBlank)
                            .collect(Collectors.toList());
                        resp = AiCloudKnowledgeBaseUtil.retrieveIndex(client, workspaceId, kbId, query, tags);
                    } else {
                        resp = AiCloudKnowledgeBaseUtil.retrieveIndex(client, workspaceId, kbId, query);
                    }
                    List<RetrieveResponseBodyDataNodes> nodes = Optional.ofNullable(resp)
                        .map(RetrieveResponse::getBody)
                        .map(RetrieveResponseBody::getData)
                        .map(RetrieveResponseBodyData::getNodes)
                        .orElse(Collections.emptyList())
                        .stream()
                        .limit(topK)
                        .collect(Collectors.toList());
                    allNodes.addAll(nodes);
                } catch (Exception e) {
                    log.warn("查询知识库失败 - kbId: {}, query: {}", kbId, query, e);
                }
            }
        } catch (Exception e) {
            log.error("创建知识库客户端失败", e);
        }
        return allNodes;
    }

    /**
     * 批量查询文件URL
     */
    protected Map<String, String> batchQueryFileUrls(List<RetrieveResponseBodyDataNodes> nodes) {
        // 收集所有文档ID
        Set<String> docIds = nodes.stream().map(this::extractDocumentId).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
        if (docIds.isEmpty()) {
            return Collections.emptyMap();
        }
        try {
            // 批量查询
            List<AiCloudFile> files = aiCloudFileService.list(new LambdaQueryWrapper<AiCloudFile>().in(AiCloudFile::getFileId, docIds));
            // 构建映射表
            return files.stream()
                .filter(file -> file.getFileUrl() != null)
                .collect(Collectors.toMap(
                    AiCloudFile::getFileId,
                    AiCloudFile::getFileUrl
                ));
        } catch (Exception e) {
            log.error("批量查询文件信息失败", e);
            return Collections.emptyMap();
        }
    }

    /**
     * 处理节点生成结果
     */
    private List<String> processNodesToResults(List<RetrieveResponseBodyDataNodes> nodes, Map<String, String> fileUrlMap) {
        Set<String> results = new LinkedHashSet<>();
        
        // 构建可用文件列表
        StringBuilder fileListBuilder = new StringBuilder();
        fileListBuilder.append("\n\n**可用真实文件列表（仅限以下文件，不得虚构其他文件名）：**\n");
        
        Set<String> processedFiles = new HashSet<>(); // 避免重复
        
        for (RetrieveResponseBodyDataNodes node : nodes) {
            try {
                // 检查文本有效性
                String text = node.getText();
                if (StrUtil.isBlank(text) || text.length() < 10) {
                    continue;
                }
                
                // 获取文档信息
                String docName = extractDocumentName(node);
                String docId = extractDocumentId(node);
                String fileUrl = fileUrlMap.get(docId);
                if (StrUtil.isBlank(fileUrl)) {
                    fileUrl = extractDocumentUrl(node);
                }
                if (StrUtil.isBlank(fileUrl)) {
                    fileUrl = "无链接";
                }
                
                // 添加文件名到列表（去重）
                if (StrUtil.isNotBlank(docName) && !processedFiles.contains(docName)) {
                    processedFiles.add(docName);
                    fileListBuilder.append("- 《").append(docName).append("》");
                    if (!"无链接".equals(fileUrl)) {
                        fileListBuilder.append(" || ").append(fileUrl);
                    }
                    fileListBuilder.append("\n");
                }
                
                // 格式化为知识库内容
                JSONObject json = new JSONObject();
                json.put("document_name", docName);
                json.put("file_url", fileUrl);
                json.put("content", text);
                String formattedText = json.toJSONString();
                results.add(formattedText);
                
            } catch (Exception e) {
                log.warn("处理知识库节点失败", e);
            }
        }
        
        // 添加文件列表到结果
        fileListBuilder.append("\n**重要约束：**\n");
        fileListBuilder.append("1. 只能使用上述列表中的文件，不得虚构其他文件名\n");
        fileListBuilder.append("2. 如果某项检查未涉及上述文件，则 workPaperIndex 填写\"[]\"\n");
        fileListBuilder.append("3. 所有文件必须来自提供的知识库内容\n");
        
        results.add(fileListBuilder.toString());
        
        return new ArrayList<>(results);
    }
    
    /**
     * 提取文档名称通用方法
     */
    protected String extractDocumentName(RetrieveResponseBodyDataNodes node) {
        try {
            Object metadataObj = node.getMetadata();
            if (metadataObj instanceof Map) {
                Map<?, ?> metadata = (Map<?, ?>) metadataObj;
                Object docNameObj = metadata.get("doc_name");
                if (docNameObj != null) {
                    return docNameObj.toString();
                }
            }
        } catch (Exception e) {
            log.debug("提取文档名称失败", e);
        }
        return "相关文档";
    }
    
    /**
     * 提取文档Id通用方法
     */
    protected String extractDocumentId(RetrieveResponseBodyDataNodes node) {
        try {
            Object metadataObj = node.getMetadata();
            if (metadataObj instanceof Map) {
                Map<?, ?> metadata = (Map<?, ?>) metadataObj;
                Object docIdObj = metadata.get("doc_id");
                if (docIdObj != null) {
                    return docIdObj.toString();
                }
            }
        } catch (Exception e) {
            log.debug("提取文档名称失败", e);
        }
        return "相关文档";
    }
    
    /**
     * 提取文档url通用方法
     */
    protected String extractDocumentUrl(RetrieveResponseBodyDataNodes node) {
        try {
            Object metadataObj = node.getMetadata();
            if (metadataObj instanceof Map) {
                Map<?, ?> metadata = (Map<?, ?>) metadataObj;
                Object docIdObj = metadata.get("doc_url");
                if (docIdObj != null) {
                    return docIdObj.toString();
                }
            }
        } catch (Exception e) {
            log.debug("提取文档名称失败", e);
        }
        return "相关文档";
    }
    
    /**
     * 构建成功响应通用方法
     */
    protected JSONObject buildSuccessResponse(JSONArray data, long startTime) {
        return buildSuccessResponse(data, startTime, null);
    }
    
    protected JSONObject buildSuccessResponse(JSONArray data, long startTime, String dataSource) {
        JSONObject result = new JSONObject();
        result.put("success", true);
        result.put("data", data);
        result.put("total_records", data.size());
        result.put("generated_time", new Date().toString());
        result.put("processing_time", (System.currentTimeMillis() - startTime) + "ms");
        if (dataSource != null) {
            result.put("data_source", dataSource);
        }
        return result;
    }
    
    /**
     * 构建失败响应通用方法
     */
    protected JSONObject buildErrorResponse(String errorMessage) {
        JSONObject result = new JSONObject();
        result.put("success", false);
        result.put("error", errorMessage);
        return result;
    }
    
    /**
     * 异步处理分类数据通用方法
     */
    protected Map<String, CompletableFuture<JSONArray>> processCategoriesAsync(
            List<String> categories, 
            CategoryProcessor processor) {
        
        Map<String, CompletableFuture<JSONArray>> futures = new LinkedHashMap<>();
        for (String category : categories) {
            CompletableFuture<JSONArray> future = processor.processCategory(category);
            futures.put(category, future);
        }
        return futures;
    }
    
    /**
     * 合并分类结果通用方法
     */
    protected JSONArray mergeCategoryResults(List<String> categoryOrder, 
                                           Map<String, CompletableFuture<JSONArray>> futures) {
        JSONArray allData = new JSONArray();
        for (String category : categoryOrder) {
            try {
                JSONArray categoryData = futures.get(category).get();
                if (categoryData != null && !categoryData.isEmpty()) {
                    allData.addAll(categoryData);
                }
            } catch (Exception e) {
                log.error("获取分类 {} 数据失败", category, e);
            }
        }
        return allData;
    }
    
    /**
     * 分类处理器函数式接口
     */
    @FunctionalInterface
    public interface CategoryProcessor {
        CompletableFuture<JSONArray> processCategory(String category);
    }
}