package com.dora.service.impl;

import com.dora.dto.provider.ProviderTaskRequest;
import com.dora.dto.provider.ProviderTaskResponse;
import com.dora.entity.AiTask;
import com.dora.entity.PointsConfig;
import com.dora.mapper.AiTaskMapper;
import com.dora.mapper.PointsConfigMapper;
import com.dora.service.AIProviderService;
import com.dora.service.NotificationService;
import com.dora.service.PointsService;
import com.dora.service.RunningHubQueueService;
import com.dora.service.provider.AIProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * RunningHub任务队列服务实现
 * 
 * <p>功能：
 * <ul>
 *   <li>控制并发轮询任务数量（默认100个）</li>
 *   <li>超出限制的任务进入等待队列</li>
 *   <li>任务完成后自动从队列中提交新任务</li>
 * </ul>
 *
 * @author 1818AI
 * @since 2025-10-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RunningHubQueueServiceImpl implements RunningHubQueueService {

    private final AiTaskMapper aiTaskMapper;
    private final PointsConfigMapper pointsConfigMapper;
    private final AIProviderService aiProviderService;
    private final NotificationService notificationService;
    private final PointsService pointsService;
    private final ObjectMapper objectMapper;

    @Value("${ai.providers.runninghub.max-polling-tasks:100}")
    private int maxPollingTasks;

    /**
     * 正在轮询的任务集合（taskNo -> AiTask）
     * 使用ConcurrentHashMap保证线程安全
     */
    private final Map<String, AiTask> pollingTasks = new ConcurrentHashMap<>();

    /**
     * 等待提交的任务队列
     * 使用LinkedBlockingQueue保证FIFO顺序和线程安全
     */
    private final LinkedBlockingQueue<AiTask> waitingQueue = new LinkedBlockingQueue<>();

    @Override
    public synchronized boolean enqueueOrSubmit(AiTask task) {
        // 1. 检查当前轮询任务数
        int currentPolling = pollingTasks.size();
        
        log.info("RunningHub队列状态 - 正在轮询: {}/{}, 等待队列: {}, 新任务: {}", 
                 currentPolling, maxPollingTasks, waitingQueue.size(), task.getTaskNo());

        // 2. 如果未达到上限，立即提交
        if (currentPolling < maxPollingTasks) {
            boolean submitted = submitToRunningHub(task);
            if (submitted) {
                pollingTasks.put(task.getTaskNo(), task);
                log.info("任务 {} 立即提交到RunningHub，当前轮询数: {}/{}", 
                         task.getTaskNo(), pollingTasks.size(), maxPollingTasks);
                return true;
            } else {
                // 提交失败，加入队列等待重试
                waitingQueue.offer(task);
                updateTaskStatus(task, "queued", "提交失败，已加入等待队列");
                log.warn("任务 {} 提交失败，加入等待队列", task.getTaskNo());
                return false;
            }
        }

        // 3. 已达到上限，加入等待队列
        waitingQueue.offer(task);
        updateTaskStatus(task, "queued", String.format("等待提交（当前轮询 %d/%d，队列位置: %d）", 
                         currentPolling, maxPollingTasks, waitingQueue.size()));
        
        log.info("任务 {} 加入等待队列，队列位置: {}", task.getTaskNo(), waitingQueue.size());
        return false;
    }

    @Override
    public int getPollingTaskCount() {
        return pollingTasks.size();
    }

    @Override
    public int getWaitingQueueSize() {
        return waitingQueue.size();
    }

    @Override
    public synchronized int processWaitingQueue() {
        int submitted = 0;
        
        // 当有空位且队列中有任务时，提交任务
        while (pollingTasks.size() < maxPollingTasks && !waitingQueue.isEmpty()) {
            AiTask task = waitingQueue.poll();
            if (task != null) {
                boolean success = submitToRunningHub(task);
                if (success) {
                    pollingTasks.put(task.getTaskNo(), task);
                    submitted++;
                    log.info("从等待队列提交任务 {} 到RunningHub，当前轮询: {}/{}, 剩余队列: {}", 
                             task.getTaskNo(), pollingTasks.size(), maxPollingTasks, waitingQueue.size());
                } else {
                    // 提交失败，重新加入队列末尾
                    waitingQueue.offer(task);
                    log.warn("任务 {} 提交失败，重新加入队列", task.getTaskNo());
                    break; // 停止处理，避免死循环
                }
            }
        }
        
        if (submitted > 0) {
            log.info("从等待队列提交了 {} 个任务，当前轮询: {}/{}, 剩余队列: {}", 
                     submitted, pollingTasks.size(), maxPollingTasks, waitingQueue.size());
        }
        
        return submitted;
    }

    @Override
    public synchronized void onTaskCompleted(String taskNo) {
        if (pollingTasks.remove(taskNo) != null) {
            log.info("任务 {} 已完成，从轮询列表移除，当前轮询: {}/{}", 
                     taskNo, pollingTasks.size(), maxPollingTasks);
            
            // 尝试处理等待队列
            processWaitingQueue();
        }
    }

    /**
     * 提交任务到RunningHub
     *
     * @param task AI任务
     * @return true=提交成功, false=提交失败
     */
    private boolean submitToRunningHub(AiTask task) {
        try {
            log.info("开始提交任务到RunningHub: {}", task.getTaskNo());

            // 1. 获取模型配置
            PointsConfig pointsConfig = pointsConfigMapper.findByModelName(task.getModelName());
            if (pointsConfig == null) {
                log.error("模型配置不存在: {}", task.getModelName());
                markTaskFailed(task, "模型配置不存在");
                return false;
            }

            // 2. 获取RunningHub Provider
            AIProvider provider = aiProviderService.getProvider(task.getModelName());
            if (provider == null) {
                log.error("未找到RunningHub Provider");
                markTaskFailed(task, "Provider不可用");
                return false;
            }

            // 3. 构建请求
            ProviderTaskRequest request = aiProviderService.buildProviderRequest(
                    task.getModelName(),
                    task.getPrompt(),
                    task.getImageUrl(),
                    task.getImageBase64(),
                    task.getAspectRatio()
            );

            // 4. 提交任务
            log.info("RunningHub任务提交中: taskNo={}, modelName={}", task.getTaskNo(), task.getModelName());
            ProviderTaskResponse response = provider.submitTask(request);
            
            log.info("RunningHub任务提交响应: taskNo={}, status={}, providerTaskId={}, error={}", 
                     task.getTaskNo(), response.getStatus(), response.getProviderTaskId(), response.getErrorMessage());

            if (response.getStatus() == ProviderTaskResponse.TaskSubmitStatus.FAILED) {
                log.error("RunningHub任务提交失败: {}, error: {}", task.getTaskNo(), response.getErrorMessage());
                
                // 检查是否是队列满的错误
                if (response.getErrorMessage() != null && 
                    response.getErrorMessage().contains("TASK_QUEUE_MAXED")) {
                    log.warn("RunningHub队列已满，任务 {} 将重新入队等待重试", task.getTaskNo());
                    // 重新入队，等待下次调度
                    task.setStatus("queued");
                    task.setErrorMessage("RunningHub队列已满，等待重试");
                    task.setUpdateTime(LocalDateTime.now());
                    aiTaskMapper.update(task);
                    
                    // 发送通知
                    notificationService.notifyTaskProgress(
                            task.getUserId(),
                            task.getTaskNo(),
                            "queued",
                            0,
                            "服务商队列已满，系统将自动重试"
                    );
                    return false;
                }
                
                // 其他错误则标记为失败
                markTaskFailed(task, "提交失败: " + response.getErrorMessage());
                return false;
            }
            
            // 验证 providerTaskId
            if (response.getProviderTaskId() == null || response.getProviderTaskId().trim().isEmpty()) {
                log.error("RunningHub任务提交响应中缺少providerTaskId: taskNo={}, response={}", 
                          task.getTaskNo(), response);
                markTaskFailed(task, "提交失败：未获取到RunningHub任务ID");
                return false;
            }

            // 5. 更新任务信息
            task.setProviderTaskId(response.getProviderTaskId());
            task.setProviderResponse(objectMapper.writeValueAsString(response.getRawResponse()));
            task.setStatus("processing");
            task.setProgressMessage("任务已提交到RunningHub，等待处理");
            task.setStartTime(LocalDateTime.now());
            task.setUpdateTime(LocalDateTime.now());
            aiTaskMapper.update(task);

            // 6. 发送WebSocket通知
            notificationService.notifyTaskProgress(
                    task.getUserId(),
                    task.getTaskNo(),
                    "processing",
                    0,
                    "任务已提交，等待RunningHub处理"
            );

            log.info("RunningHub任务提交成功: {}, providerTaskId: {}", 
                     task.getTaskNo(), response.getProviderTaskId());
            return true;

        } catch (Exception e) {
            log.error("提交RunningHub任务异常: {}", task.getTaskNo(), e);
            markTaskFailed(task, "提交异常: " + e.getMessage());
            return false;
        }
    }

    /**
     * 更新任务状态
     */
    private void updateTaskStatus(AiTask task, String status, String message) {
        try {
            task.setStatus(status);
            task.setProgressMessage(message);
            task.setUpdateTime(LocalDateTime.now());
            aiTaskMapper.update(task);

            // 发送通知
            notificationService.notifyTaskProgress(
                    task.getUserId(),
                    task.getTaskNo(),
                    status,
                    task.getProgress() != null ? task.getProgress() : 0,
                    message
            );
        } catch (Exception e) {
            log.error("更新任务状态失败: {}", task.getTaskNo(), e);
        }
    }

    /**
     * 标记任务失败
     */
    private void markTaskFailed(AiTask task, String errorMessage) {
        try {
            task.setStatus("failed");
            task.setErrorMessage(errorMessage);
            task.setCompleteTime(LocalDateTime.now());
            task.setUpdateTime(LocalDateTime.now());
            aiTaskMapper.update(task);

            // 退还积分
            if (task.getPointsFrozen() != null && task.getPointsFrozen() > 0) {
                pointsService.refundPoints(
                        task.getUserId(),
                        task.getPointsFrozen(),
                        task.getTaskNo(),
                        "任务提交失败，退还积分"
                );
            }

            // 发送通知
            notificationService.notifyTaskFailed(task.getUserId(), task.getTaskNo(), errorMessage);
        } catch (Exception e) {
            log.error("标记任务失败时出错: {}", task.getTaskNo(), e);
        }
    }

    /**
     * 获取当前正在轮询的任务列表（用于调试）
     */
    public Set<String> getPollingTaskNos() {
        return pollingTasks.keySet();
    }
}


