package com.lingyue.parse.service;

import com.lingyue.parse.config.RabbitMQConfig;
import com.lingyue.parse.dto.ParseTaskMessage;
import com.lingyue.parse.enums.FileType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

/**
 * 解析任务消息消费者
 * 从RabbitMQ队列中消费解析任务
 * 
 * @author lingyue
 * @since 2026-01-14
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ParseTaskMessageConsumer {
    
    private final ParseService parseService;
    private final RabbitTemplate rabbitTemplate;
    
    /**
     * 消费解析任务消息
     * 
     * @param message 解析任务消息
     */
    @RabbitListener(queues = RabbitMQConfig.PARSE_TASK_QUEUE)
    public void consumeParseTask(ParseTaskMessage message) {
        log.info("收到解析任务消息: documentId={}, fileType={}, retryCount={}", 
                message.getDocumentId(), message.getFileType(), message.getRetryCount());
        
        try {
            FileType fileType = FileType.valueOf(message.getFileType());
            parseService.parseAndSaveText(
                    message.getDocumentId(),
                    message.getSourceFilePath(),
                    fileType
            );
            
            log.info("解析任务处理成功: documentId={}", message.getDocumentId());
        } catch (Exception e) {
            log.error("解析任务处理失败: documentId={}, retryCount={}", 
                    message.getDocumentId(), message.getRetryCount(), e);
            
            // 如果未达到最大重试次数，发送到重试队列
            if (message.getRetryCount() < message.getMaxRetries()) {
                handleRetry(message, e);
            } else {
                log.error("解析任务已达到最大重试次数，发送到死信队列: documentId={}", 
                        message.getDocumentId());
                handleDeadLetter(message, e);
            }
        }
    }
    
    /**
     * 消费重试队列中的任务
     * 延迟一段时间后重新处理
     * 
     * @param message 解析任务消息
     */
    @RabbitListener(queues = RabbitMQConfig.PARSE_TASK_RETRY_QUEUE)
    public void consumeRetryTask(ParseTaskMessage message) {
        log.info("收到重试任务: documentId={}, retryCount={}", 
                message.getDocumentId(), message.getRetryCount());
        
        // 延迟重试：重试次数越多，延迟越长（指数退避）
        long delayMs = 1000L * (long) Math.pow(2, message.getRetryCount());
        
        try {
            Thread.sleep(delayMs);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("重试延迟被中断", e);
            return;
        }
        
        // 重新发送到主队列处理
        try {
            rabbitTemplate.convertAndSend(RabbitMQConfig.PARSE_TASK_QUEUE, message);
            log.info("重试任务已重新发送到主队列: documentId={}, retryCount={}", 
                    message.getDocumentId(), message.getRetryCount());
        } catch (Exception e) {
            log.error("重新发送重试任务失败，发送到死信队列: documentId={}", 
                    message.getDocumentId(), e);
            handleDeadLetter(message, e);
        }
    }
    
    /**
     * 处理重试
     * 增加重试次数并发送到重试队列
     */
    private void handleRetry(ParseTaskMessage message, Exception e) {
        message.setRetryCount(message.getRetryCount() + 1);
        
        try {
            // 发送到重试队列
            rabbitTemplate.convertAndSend(RabbitMQConfig.PARSE_TASK_RETRY_QUEUE, message);
            log.warn("解析任务已发送到重试队列: documentId={}, retryCount={}", 
                    message.getDocumentId(), message.getRetryCount());
        } catch (Exception ex) {
            log.error("发送重试任务失败: documentId={}", message.getDocumentId(), ex);
            // 如果发送重试队列失败，直接发送到死信队列
            handleDeadLetter(message, e);
        }
    }
    
    /**
     * 处理死信
     * 发送到死信队列，记录失败任务
     */
    private void handleDeadLetter(ParseTaskMessage message, Exception e) {
        try {
            // 发送到死信队列
            rabbitTemplate.convertAndSend(RabbitMQConfig.PARSE_TASK_DLQ, message);
            log.error("解析任务已发送到死信队列: documentId={}, error={}", 
                    message.getDocumentId(), e.getMessage());
        } catch (Exception ex) {
            log.error("发送死信队列失败: documentId={}", message.getDocumentId(), ex);
        }
    }
}
