package com.lingyue.graph.listener;

import com.lingyue.common.event.DocumentParsedEvent;
import com.lingyue.document.entity.Document;
import com.lingyue.document.repository.DocumentRepository;
import com.lingyue.graph.service.GraphNerService;
import com.lingyue.graph.service.NerToBlockService;
import com.lingyue.graph.service.NerToBlockService.TextElementDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * 文档解析完成事件监听器
 * 监听文档解析完成事件，自动触发后续处理流程：
 * 1. 结构化解析（Word 文档 -> 段落/图片/表格）
 * 2. NER 实体提取（文本 -> 实体/关系）
 * 
 * 所有步骤同时支持手动触发 API，可单独重新生成
 *
 * @author lingyue
 * @since 2026-01-19
 * @updated 2026-01-21 增加自动结构化解析
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DocumentParsedEventListener {

    private final GraphNerService graphNerService;
    private final NerToBlockService nerToBlockService;
    private final RestTemplate restTemplate;
    private final DocumentRepository documentRepository;

    @Value("${ner.auto-extract.enabled:true}")
    private boolean nerAutoExtractEnabled;
    
    @Value("${parse.structured.auto-extract.enabled:true}")
    private boolean structuredAutoExtractEnabled;
    
    @Value("${server.port:5232}")
    private int serverPort;

    @Value("${ner.python-service.url:http://localhost:8001}")
    private String nerServiceUrl;
    
    @Value("${ner.python-service.use-async:true}")
    private boolean useAsyncApi;
    
    @Value("${ner.python-service.poll-interval:3000}")
    private long pollInterval;  // 轮询间隔（毫秒）
    
    @Value("${ner.python-service.max-wait-time:600000}")
    private long maxWaitTime;  // 最大等待时间（毫秒）

    /**
     * 处理文档解析完成事件
     * 异步执行后续处理流程，不阻塞主流程
     * 
     * 处理顺序：
     * 1. 结构化解析（Word 文档提取段落/图片/表格）
     * 2. NER 实体提取（文本提取实体/关系）
     */
    @Async
    @EventListener
    public void handleDocumentParsedEvent(DocumentParsedEvent event) {
        String documentId = event.getDocumentId();
        String userId = event.getUserId();
        
        log.info("收到文档解析完成事件: documentId={}, userId={}", documentId, userId);
        
        long totalStartTime = System.currentTimeMillis();
        
        // Step 1: 结构化解析（仅 Word 文档）
        if (structuredAutoExtractEnabled) {
            triggerStructuredExtraction(documentId);
        }
        
        // Step 2: NER 实体提取
        if (nerAutoExtractEnabled) {
            triggerNerExtraction(documentId, userId);
        }
        
        long totalTime = System.currentTimeMillis() - totalStartTime;
        log.info("文档后处理完成: documentId={}, totalTime={}ms", documentId, totalTime);
    }
    
    /**
     * 触发结构化解析
     * 仅对 Word 文档有效，提取段落、图片、表格
     */
    private void triggerStructuredExtraction(String documentId) {
        try {
            // 检查是否是 Word 文档
            Document document = documentRepository.selectById(documentId);
            if (document == null) {
                log.warn("文档不存在，跳过结构化解析: documentId={}", documentId);
                return;
            }
            
            String docType = document.getType();
            if (!"word".equalsIgnoreCase(docType)) {
                log.debug("非 Word 文档，跳过结构化解析: documentId={}, type={}", documentId, docType);
                // 标记为完成（非Word文档无需结构化解析）
                updateTaskProgress(documentId, "structured", "completed", 100, null);
                return;
            }
            
            log.info("开始自动结构化解析: documentId={}", documentId);
            long startTime = System.currentTimeMillis();
            
            // 更新进度：开始
            updateTaskProgress(documentId, "structured", "processing", 10, null);
            
            // 调用本地 API 触发结构化解析
            String url = "http://localhost:" + serverPort + "/parse/structured/" + documentId;
            
            ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
            
            if (response.getStatusCode().is2xxSuccessful()) {
                long time = System.currentTimeMillis() - startTime;
                log.info("结构化解析完成: documentId={}, time={}ms", documentId, time);
                
                // 提取结果信息并更新进度
                Map<String, Object> data = (Map<String, Object>) response.getBody().get("data");
                if (data != null) {
                    Map<String, Object> progressData = new HashMap<>();
                    progressData.put("status", "completed");
                    progressData.put("progress", 100);
                    progressData.put("elementCount", data.get("totalElements"));
                    progressData.put("imageCount", data.get("imageCount"));
                    progressData.put("tableCount", data.get("tableCount"));
                    updateTaskProgress(documentId, "structured", progressData);
                }
            } else {
                log.warn("结构化解析失败: documentId={}, status={}", documentId, response.getStatusCode());
                updateTaskProgress(documentId, "structured", "failed", 0, null);
            }
            
        } catch (Exception e) {
            log.error("自动结构化解析异常: documentId={}, error={}", documentId, e.getMessage());
            updateTaskProgress(documentId, "structured", "failed", 0, null);
            // 异常不向上抛出，不影响后续处理
        }
    }
    
    /**
     * 触发 NER 实体提取
     */
    private void triggerNerExtraction(String documentId, String userId) {
        long startTime = System.currentTimeMillis();

        try {
            // 1. 获取文档文本
            if (!graphNerService.hasDocumentText(documentId)) {
                log.warn("文档文本不存在，跳过 NER: documentId={}", documentId);
                return;
            }
            
            String text = graphNerService.getDocumentText(documentId);
            if (text == null || text.isEmpty()) {
                log.warn("文档文本为空，跳过 NER: documentId={}", documentId);
                return;
            }
            
            log.info("开始自动 NER 提取: documentId={}", documentId);
            
            // 更新进度：开始
            updateTaskProgress(documentId, "ner", "processing", 5, null);

            // 2. 调用 Python NER 服务（根据配置选择异步轮询或同步 API）
            Map<String, Object> nerResponse;
            if (useAsyncApi) {
                nerResponse = callPythonNerServiceAsync(documentId, text, userId);
            } else {
                nerResponse = callPythonNerService(documentId, text, userId);
            }
            
            if (nerResponse == null || !Boolean.TRUE.equals(nerResponse.get("success"))) {
                log.warn("NER 服务调用失败: documentId={}, error={}", 
                        documentId, nerResponse != null ? nerResponse.get("errorMessage") : "null response");
                updateTaskProgress(documentId, "ner", "failed", 0, null);
                return;
            }
            
            // 更新进度：NER 完成，开始保存
            updateTaskProgress(documentId, "ner", "processing", 80, null);
            
            // 更新图构建进度：开始
            updateTaskProgress(documentId, "graph", "processing", 10, null);

            // 3. 保存实体到图数据库
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> entities = (List<Map<String, Object>>) nerResponse.get("entities");
            Map<String, String> tempIdToNodeId = graphNerService.saveEntitiesToGraph(documentId, userId, entities);
            
            // 更新图构建进度
            updateTaskProgress(documentId, "graph", "processing", 50, null);

            // 4. 保存关系到图数据库
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> relations = (List<Map<String, Object>>) nerResponse.get("relations");
            int relationCount = graphNerService.saveRelationsToGraph(relations, tempIdToNodeId);
            
            // 5. 将 NER 结果转换为 TextElement 格式（用于结构化文档）
            List<TextElementDTO> textElements = nerToBlockService.convertToTextElements(text, entities);
            log.debug("NER 结果已转换为 TextElement: documentId={}, elementCount={}", 
                    documentId, textElements.size());

            long processingTime = System.currentTimeMillis() - startTime;
            
            // 更新 NER 完成进度
            int entityCount = entities != null ? entities.size() : 0;
            Map<String, Object> nerProgressData = new HashMap<>();
            nerProgressData.put("status", "completed");
            nerProgressData.put("progress", 100);
            nerProgressData.put("entityCount", entityCount);
            nerProgressData.put("relationCount", relationCount);
            updateTaskProgress(documentId, "ner", nerProgressData);
            
            // 更新图构建完成进度
            updateTaskProgress(documentId, "graph", "completed", 100, null);
            
            log.info("NER 自动提取完成: documentId={}, entityCount={}, relationCount={}, time={}ms",
                    documentId, entityCount, relationCount, processingTime);

        } catch (Exception e) {
            log.error("NER 自动提取异常: documentId={}", documentId, e);
            updateTaskProgress(documentId, "ner", "failed", 0, null);
            // 异常不向上抛出，不影响其他处理
        }
    }

    /**
     * 调用 Python NER 服务（同步 REST API）
     */
    private Map<String, Object> callPythonNerService(String documentId, String text, String userId) {
        try {
            String url = nerServiceUrl + "/ner/extract";
            
            Map<String, Object> request = new HashMap<>();
            request.put("documentId", documentId);
            request.put("text", text);
            request.put("userId", userId);
            request.put("extractRelations", true);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(request, headers);
            
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.POST, entity, Map.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                @SuppressWarnings("unchecked")
                Map<String, Object> body = response.getBody();
                return body;
            }
            
            return null;
            
        } catch (Exception e) {
            log.error("调用 Python NER 服务失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 调用 Python NER 服务（异步 + 轮询模式）
     * 
     * 流程：
     * 1. 提交异步任务，立即获得 task_id
     * 2. 定期轮询任务状态
     * 3. 任务完成后获取结果
     */
    private Map<String, Object> callPythonNerServiceAsync(String documentId, String text, String userId) {
        try {
            // 1. 提交异步任务
            String submitUrl = nerServiceUrl + "/ner/extract/async";
            
            Map<String, Object> request = new HashMap<>();
            request.put("documentId", documentId);
            request.put("text", text);
            request.put("userId", userId);
            request.put("extractRelations", true);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(request, headers);
            
            @SuppressWarnings("unchecked")
            ResponseEntity<Map<String, Object>> submitResponse = restTemplate.exchange(
                    submitUrl, HttpMethod.POST, entity, 
                    (Class<Map<String, Object>>) (Class<?>) Map.class);
            
            if (!submitResponse.getStatusCode().is2xxSuccessful() || submitResponse.getBody() == null) {
                log.error("提交异步 NER 任务失败: documentId={}", documentId);
                return null;
            }
            
            String taskId = (String) submitResponse.getBody().get("task_id");
            log.info("异步 NER 任务已提交: documentId={}, taskId={}", documentId, taskId);
            
            // 2. 轮询任务状态
            String statusUrl = nerServiceUrl + "/ner/task/" + taskId;
            long startTime = System.currentTimeMillis();
            int lastProgress = -1;
            
            while (System.currentTimeMillis() - startTime < maxWaitTime) {
                try {
                    Thread.sleep(pollInterval);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.warn("轮询被中断: taskId={}", taskId);
                    break;
                }
                
                try {
                    @SuppressWarnings("unchecked")
                    ResponseEntity<Map<String, Object>> statusResponse = restTemplate.exchange(
                            statusUrl, HttpMethod.GET, null,
                            (Class<Map<String, Object>>) (Class<?>) Map.class);
                    
                    if (!statusResponse.getStatusCode().is2xxSuccessful() || statusResponse.getBody() == null) {
                        log.warn("查询任务状态失败: taskId={}", taskId);
                        continue;
                    }
                    
                    Map<String, Object> taskStatus = statusResponse.getBody();
                    String status = (String) taskStatus.get("status");
                    int progress = taskStatus.get("progress") != null ? 
                            ((Number) taskStatus.get("progress")).intValue() : 0;
                    String message = (String) taskStatus.get("message");
                    
                    // 只在进度变化时打印日志
                    if (progress != lastProgress) {
                        log.info("NER 进度: documentId={}, taskId={}, status={}, progress={}%, message={}", 
                                documentId, taskId, status, progress, message);
                        lastProgress = progress;
                    }
                    
                    // 检查任务是否完成
                    if ("completed".equals(status)) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> result = (Map<String, Object>) taskStatus.get("result");
                        log.info("异步 NER 任务完成: documentId={}, taskId={}", documentId, taskId);
                        
                        // 删除任务（释放服务端内存）
                        try {
                            restTemplate.delete(statusUrl);
                        } catch (Exception e) {
                            log.debug("删除任务失败（可忽略）: taskId={}", taskId);
                        }
                        
                        return result;
                    } else if ("failed".equals(status)) {
                        String error = (String) taskStatus.get("error");
                        log.error("异步 NER 任务失败: documentId={}, taskId={}, error={}", documentId, taskId, error);
                        return null;
                    }
                    
                } catch (Exception e) {
                    log.warn("轮询任务状态异常: taskId={}, error={}", taskId, e.getMessage());
                }
            }
            
            log.error("异步 NER 任务超时: documentId={}, taskId={}, maxWaitTime={}ms", 
                    documentId, taskId, maxWaitTime);
            return null;
            
        } catch (Exception e) {
            log.error("调用异步 NER 服务失败: documentId={}, error={}", documentId, e.getMessage(), e);
            // 回退到同步 API
            log.info("回退到同步 NER API: documentId={}", documentId);
            return callPythonNerService(documentId, text, userId);
        }
    }
    
    // ==================== 任务进度更新 ====================
    
    /**
     * 更新任务进度（简单版本）
     */
    private void updateTaskProgress(String documentId, String stage, String status, Integer progress, String errorMessage) {
        Map<String, Object> data = new HashMap<>();
        data.put("status", status);
        data.put("progress", progress);
        if (errorMessage != null) {
            data.put("errorMessage", errorMessage);
        }
        updateTaskProgress(documentId, stage, data);
    }
    
    /**
     * 更新任务进度（完整版本）
     */
    private void updateTaskProgress(String documentId, String stage, Map<String, Object> data) {
        try {
            String url = "http://localhost:" + serverPort + "/api/internal/task-progress/" + stage + "/" + documentId;
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(data, headers);
            
            restTemplate.postForEntity(url, entity, Map.class);
            
        } catch (Exception e) {
            // 进度更新失败不影响主流程
            log.debug("更新任务进度失败（可忽略）: documentId={}, stage={}, error={}", 
                    documentId, stage, e.getMessage());
        }
    }
}
