package com.example.demo.service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.model.TaskStatus;
import com.example.demo.model.UserWork;
import com.example.demo.model.StoryboardVideoTask;
import com.example.demo.model.enums.CommonTaskType;
import com.example.demo.repository.TaskStatusRepository;
import com.example.demo.config.DynamicApiConfig;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.annotation.PostConstruct;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;

/**
 * 任务状态轮询服务（外部 API 结果跟踪）
 * 
 * 核心职责：
 * 1. 定期轮询外部 AI API，获取已提交任务的最新状态（pollTaskStatuses）
 * 2. 将轮询结果写入 task_status 表，并通过级联更新同步到业务任务表和 user_works
 * 3. 提供 markTaskCompleted / markTaskFailed 方法，供其他服务触发级联状态更新
 * 
 * 调用关系：
 * - TaskQueueScheduler 每 2 分钟调用 pollTaskStatuses()
 * - 轮询到终态后，回调 TaskQueueService.handleTaskCompletionByTaskId / handleTaskFailureByTaskId
 * - 级联更新路径：task_status -> 业务任务表(text_to_video_tasks 等) -> user_works -> 积分返还 -> 错误日志
 * 
 * @see TaskQueueService
 */
@Service
public class TaskStatusPollingService {
    
    private static final Logger logger = LoggerFactory.getLogger(TaskStatusPollingService.class);
    
    // 任务超时时间（小时）
    private static final int TASK_TIMEOUT_HOURS = 1;
    
    // 记录已经记录过失败日志的任务ID，避免重复记录
    private final Set<String> loggedFailedTaskIds = ConcurrentHashMap.newKeySet();
    
    @Autowired
    private TaskStatusRepository taskStatusRepository;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Autowired
    @org.springframework.context.annotation.Lazy
    private TaskQueueService taskQueueService;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private com.example.demo.repository.StoryboardVideoTaskRepository storyboardVideoTaskRepository;
    
    @Autowired
    private com.example.demo.repository.ImageToVideoTaskRepository imageToVideoTaskRepository;
    
    @Autowired
    private com.example.demo.repository.TextToVideoTaskRepository textToVideoTaskRepository;
    
    @Autowired
    private UserErrorLogService userErrorLogService;
    
    @Autowired
    private DynamicApiConfig dynamicApiConfig;
    
    @Autowired
    private UserWorkService userWorkService;
    
    /**
     * 系统启动时恢复处理中的任务
     * - 对所有 PROCESSING 状态的任务进行一次状态查询
     * - 如果外部API返回已完成，则标记成功
     * - 如果超时（创建时间超过1小时），则标记失败
     * - 如果未超时且未完成，保持现状等待后续轮询
     */
    @PostConstruct
    public void recoverProcessingTasksOnStartup() {
        logger.info("=== 系统启动：开始恢复处理中的任务 ===");
        
        try {
            // 查找所有 PROCESSING 状态的任务
            List<TaskStatus> processingTasks = taskStatusRepository.findAllByStatus(TaskStatus.Status.PROCESSING);
            
            if (processingTasks.isEmpty()) {
                logger.info("没有需要恢复的处理中任务");
                return;
            }
            
            logger.info("发现 {} 个处理中的任务，开始恢复检查...", processingTasks.size());
            
            for (TaskStatus task : processingTasks) {
                try {
                    recoverSingleTask(task);
                } catch (Exception e) {
                    logger.error("恢复任务 {} 时发生错误: {}", task.getTaskId(), e.getMessage(), e);
                }
            }
            
            logger.info("=== 系统启动：任务恢复检查完成 ===");
            
        } catch (Exception e) {
            logger.error("系统启动恢复任务时发生错误: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 恢复单个任务
     */
    private void recoverSingleTask(TaskStatus task) {
        logger.info("恢复检查任务: taskId={}, externalTaskId={}, createdAt={}", 
            task.getTaskId(), task.getExternalTaskId(), task.getCreatedAt());
        
        // 检查是否有外部任务ID
        if (task.getExternalTaskId() == null || task.getExternalTaskId().isEmpty()) {
            // 没有外部任务ID，检查是否超时
            if (isTaskTimeout(task)) {
                logger.warn("任务 {} 无外部任务ID且已超时，标记为失败", task.getTaskId());
                task.markAsFailed("任务超时：未获取到外部任务ID");
                taskStatusRepository.save(task);
                // 同步更新业务表、UserWork 等，并记录错误日志
                taskQueueService.handleTaskFailureByTaskId(task.getTaskId(), "任务超时：未获取到外部任务ID");
            } else {
                logger.info("任务 {} 无外部任务ID但未超时，保持现状", task.getTaskId());
            }
            return;
        }
        
        // 有外部任务ID，查询外部API状态（最多重试3次）
        int maxRetries = 3;
        int retryCount = 0;
        boolean apiQuerySuccess = false;
        String lastError = null;
        
        while (retryCount < maxRetries && !apiQuerySuccess) {
            retryCount++;
            try {
                logger.info("恢复检查任务 {} 外部API状态（第{}次尝试）", task.getTaskId(), retryCount);
                
                String url = dynamicApiConfig.getApiBaseUrl() + "/v2/videos/generations/" + task.getExternalTaskId();
                HttpResponse<String> response = Unirest.get(url)
                    .header("Authorization", "Bearer " + dynamicApiConfig.getApiKey())
                    .asString();
                
                if (response.getStatus() == 200) {
                    apiQuerySuccess = true;
                    JsonNode responseJson = objectMapper.readTree(response.getBody());
                    String status = responseJson.path("status").asText();
                    String resultUrl = responseJson.path("data").path("output").asText();
                    
                    logger.info("外部API返回: taskId={}, status={}, resultUrl={}", 
                        task.getTaskId(), status, resultUrl);
                    
                    if ("SUCCESS".equalsIgnoreCase(status) && resultUrl != null && !resultUrl.isEmpty()) {
                        // 任务已完成，标记成功并同步更新所有表
                        task.markAsCompleted(resultUrl);
                        taskStatusRepository.save(task);
                        logger.info("任务 {} 恢复为已完成状态，resultUrl={}", task.getTaskId(), resultUrl);
                        // 同步更新业务表、UserWork 等
                        taskQueueService.handleTaskCompletionByTaskId(task.getTaskId(), resultUrl);
                    } else if ("FAILED".equalsIgnoreCase(status) || "FAILURE".equalsIgnoreCase(status) || "ERROR".equalsIgnoreCase(status)) {
                        // 任务失败
                        String failReason = responseJson.path("fail_reason").asText("外部API返回失败");
                        task.markAsFailed(failReason);
                        taskStatusRepository.save(task);
                        // 只在第一次记录失败日志
                        if (loggedFailedTaskIds.add(task.getTaskId())) {
                            logger.warn("任务 {} 恢复为失败状态，原因: {}", task.getTaskId(), failReason);
                        }
                        // 同步更新业务表、UserWork 等
                        taskQueueService.handleTaskFailureByTaskId(task.getTaskId(), failReason);
                    } else {
                        // 任务仍在处理中，检查是否超时
                        if (isTaskTimeout(task)) {
                            // 只在第一次记录失败日志
                            if (loggedFailedTaskIds.add(task.getTaskId())) {
                                logger.warn("任务 {} 已超时，标记为失败", task.getTaskId());
                            }
                            task.markAsFailed("任务超时");
                            taskStatusRepository.save(task);
                            // 同步更新业务表、UserWork 等
                            taskQueueService.handleTaskFailureByTaskId(task.getTaskId(), "任务超时");
                        } else {
                            logger.info("任务 {} 仍在处理中且未超时，保持现状", task.getTaskId());
                        }
                    }
                } else {
                    lastError = "HTTP状态码: " + response.getStatus();
                    logger.warn("查询任务状态失败（第{}次）: taskId={}, status={}", retryCount, task.getTaskId(), response.getStatus());
                }
            } catch (Exception e) {
                lastError = e.getMessage();
                logger.warn("查询外部API失败（第{}次）: taskId={}, error={}", retryCount, task.getTaskId(), e.getMessage());
            }
            
            // 如果还需要重试，等待1秒
            if (!apiQuerySuccess && retryCount < maxRetries) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
        
        // 如果3次查询都失败
        if (!apiQuerySuccess) {
            // 检查是否超时
            if (isTaskTimeout(task)) {
                logger.warn("任务 {} 连续{}次查询外部API失败且已超时，标记为失败（最后错误: {}）", 
                    task.getTaskId(), maxRetries, lastError);
                task.markAsFailed("任务超时：连续" + maxRetries + "次查询外部API失败");
                taskStatusRepository.save(task);
                taskQueueService.handleTaskFailureByTaskId(task.getTaskId(), "任务超时：连续" + maxRetries + "次查询外部API失败");
            } else {
                // 未超时，保持现状让后续轮询继续处理
                logger.warn("任务 {} 连续{}次查询外部API失败，但未超时，保持现状继续轮询（最后错误: {}）", 
                    task.getTaskId(), maxRetries, lastError);
            }
        }
    }
    
    /**
     * 检查任务是否超时（创建时间超过1小时）
     */
    private boolean isTaskTimeout(TaskStatus task) {
        if (task.getCreatedAt() == null) {
            return false;
        }
        long hoursSinceCreation = ChronoUnit.HOURS.between(task.getCreatedAt(), LocalDateTime.now());
        return hoursSinceCreation >= TASK_TIMEOUT_HOURS;
    }
    
    /**
     * 根据状态查找任务列表
     */
    public List<TaskStatus> findByStatus(TaskStatus.Status status) {
        return taskStatusRepository.findByStatus(status, org.springframework.data.domain.Pageable.unpaged()).getContent();
    }
    
    /**
     * (Scheduling disabled) 原先每2分钟执行一次轮询查询任务状态。
     * 注意：调度已集中到 `TaskQueueScheduler.checkTaskStatuses()`，以避免重复并发查询。
     * 如果你更希望这个服务自己轮询，可以将 @Scheduled 注解恢复到此方法。
     */
    // @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void pollTaskStatuses() {
        logger.info("=== 开始执行任务状态轮询查询 (每2分钟) ===");
        
        try {
            // 查找需要轮询的任务（上次轮询时间超过2分钟）
            LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(2);
            // 先做一次计数，避免在无任务时加载实体列表
            long needCount = taskStatusRepository.countTasksNeedingPolling(cutoffTime);

            logger.info("需要轮询查询的任务数量: {}", needCount);

            if (needCount == 0) {
                // 检查是否有PROCESSING任务但不满足轮询条件
                long processingCount = taskStatusRepository.countByStatus(TaskStatus.Status.PROCESSING);
                if (processingCount > 0) {
                    logger.debug("有 {} 个PROCESSING任务，但均在冷却期内（2分钟内已轮询过）", processingCount);
                }
                return;
            }

            List<TaskStatus> tasksToPoll = taskStatusRepository.findTasksNeedingPolling(cutoffTime);
            
            // 逐个轮询任务状态
            for (TaskStatus task : tasksToPoll) {
                try {
                    logger.info("轮询任务: taskId={}, externalTaskId={}, status={}", 
                        task.getTaskId(), task.getExternalTaskId(), task.getStatus());
                    pollTaskStatus(task);
                } catch (Exception e) {
                    logger.error("轮询任务 {} 时发生错误: {}", task.getTaskId(), e.getMessage(), e);
                }
            }
            
            // 处理超时任务
            handleTimeoutTasks();
            
            logger.info("=== 任务状态轮询查询完成 ===");
            
        } catch (Exception e) {
            logger.error("轮询任务状态时发生错误: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 轮询单个任务状态
     * 注意：此方法明确禁用事务，因为长时间运行的外部API调用会占用数据库连接
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void pollTaskStatus(TaskStatus task) {
        logger.info("轮询任务状态: taskId={}, externalTaskId={}", task.getTaskId(), task.getExternalTaskId());
        
        // 检查 externalTaskId 是否为空
        if (task.getExternalTaskId() == null || task.getExternalTaskId().isEmpty()) {
            // 对于分镜图任务（sb_ 开头），可能是同步处理的，不需要外部轮询
            // 只对需要外部轮询的视频任务（txt2vid_, img2vid_）标记失败
            String taskId = task.getTaskId();
            boolean isVideoTask = taskId != null && (taskId.startsWith("txt2vid_") || taskId.startsWith("img2vid_"));
            
            if (isVideoTask) {
                // 增加时间窗口保护：只有任务创建超过5分钟后 externalTaskId 仍为空才标记为失败
                // 避免任务刚创建还在等待提交到外部API时就被错误地标记为失败
                java.time.LocalDateTime fiveMinutesAgo = java.time.LocalDateTime.now().minusMinutes(5);
                if (task.getCreatedAt() != null && task.getCreatedAt().isAfter(fiveMinutesAgo)) {
                    logger.debug("任务 {} 的 externalTaskId 为空，但创建时间未超过5分钟，跳过本次轮询", taskId);
                    return;
                }
                
                // 只在第一次记录失败日志
                if (loggedFailedTaskIds.add(taskId)) {
                    logger.warn("视频任务 {} 的 externalTaskId 为空且已超过5分钟，标记为失败并返还积分", taskId);
                }
                String errorMessage = "任务提交失败：未能成功提交到外部API，请检查网络或稍后重试";
                markTaskFailed(taskId, errorMessage);
                
                // 返还积分
                try {
                    userService.returnFrozenPoints(taskId);
                    logger.info("已返还任务 {} 的冻结积分", taskId);
                } catch (Exception e) {
                    logger.warn("返还积分失败（可能已处理）: taskId={}", taskId);
                }
            } else {
                // 分镜图任务跳过，由 StoryboardVideoService 自己处理
                logger.debug("分镜任务 {} 无 externalTaskId，跳过轮询（由业务层处理）", taskId);
            }
            return;
        }
        
        String[] pendingAction = null;
        
        try {
            // 使用正确的 API 端点：GET /v2/videos/generations/{task_id}
            String url = dynamicApiConfig.getApiBaseUrl() + "/v2/videos/generations/" + task.getExternalTaskId();
            HttpResponse<String> response = Unirest.get(url)
                .header("Authorization", "Bearer " + dynamicApiConfig.getApiKey())
                .asString();
            
            if (response.getStatus() == 200) {
                JsonNode responseJson = objectMapper.readTree(response.getBody());
                logger.info("轮询任务状态成功: taskId={}, response={}", task.getTaskId(), response.getBody());
                // 更新任务状态（使用单独的事务方法），返回需要后续处理的信息
                pendingAction = updateTaskStatusWithTransaction(task, responseJson);
            } else {
                logger.warn("查询任务状态失败: taskId={}, status={}, response={}", 
                    task.getTaskId(), response.getStatus(), response.getBody());
                // 更新轮询次数（使用单独的事务方法）
                incrementPollCountWithTransaction(task);
                
                // 检查是否超时，超时则标记失败
                if (isTaskTimeout(task)) {
                    String errorMessage = "任务超时：外部API返回错误状态码 " + response.getStatus();
                    markTaskFailed(task.getTaskId(), errorMessage);
                    pendingAction = new String[]{"FAILED", task.getTaskId(), errorMessage};
                }
            }
            
        } catch (Exception e) {
            logger.error("轮询任务状态异常: taskId={}, error={}", task.getTaskId(), e.getMessage(), e);
            // 更新轮询次数（使用单独的事务方法）
            incrementPollCountWithTransaction(task);
            
            // 检查是否超时，超时则标记失败
            if (isTaskTimeout(task)) {
                String errorMessage = "任务超时：轮询异常 - " + e.getMessage();
                markTaskFailed(task.getTaskId(), errorMessage);
                pendingAction = new String[]{"FAILED", task.getTaskId(), errorMessage};
            }
        }
        
        // 在事务外处理后续操作（避免事务超时）
        if (pendingAction != null) {
            try {
                String actionType = pendingAction[0];
                String taskId = pendingAction[1];
                String data = pendingAction[2];
                
                if ("COMPLETED".equals(actionType)) {
                    taskQueueService.handleTaskCompletionByTaskId(taskId, data);
                } else if ("FAILED".equals(actionType)) {
                    taskQueueService.handleTaskFailureByTaskId(taskId, data);
                }
            } catch (Exception e) {
                logger.error("处理任务后续操作失败: {}", e.getMessage(), e);
            }
        }
    }

    /**
     * 更新任务状态（单独的事务方法）- 只更新 TaskStatus 表
     * 返回值：null=无需后续处理, [0]=完成需处理, [1]=失败需处理
     */
    @Transactional
    public String[] updateTaskStatusWithTransaction(TaskStatus task, JsonNode responseJson) {
        return updateTaskStatusOnly(task, responseJson);
    }

    /**
     * 增加轮询次数（单独的事务方法）
     */
    @Transactional
    public void incrementPollCountWithTransaction(TaskStatus task) {
        task.incrementPollCount();
        taskStatusRepository.save(task);
    }
    
    /**
     * 更新任务状态 - 只更新 TaskStatus 表，返回后续需要处理的信息
     * 返回：[taskId, resultUrl] 表示完成，[taskId, null, errorMessage] 表示失败，null 表示无需后续处理
     */
    private String[] updateTaskStatusOnly(TaskStatus task, JsonNode responseJson) {
        try {
            String status = responseJson.path("status").asText();
            String progressStr = responseJson.path("progress").asText("0%");
            int progress = parseProgress(progressStr);
            // API 返回的视频URL在 data.output 中
            String resultUrl = responseJson.path("data").path("output").asText();
            String errorMessage = responseJson.path("fail_reason").asText();
            
            task.incrementPollCount();
            task.setProgress(progress);
            
            switch (status.toLowerCase()) {
                case "completed":
                case "success":
                    if (resultUrl != null && !resultUrl.isEmpty()) {
                        task.markAsCompleted(resultUrl);
                        logger.info("任务完成: taskId={}, resultUrl={}", task.getTaskId(), resultUrl);
                        taskStatusRepository.save(task);
                        // 返回任务信息，在事务外处理
                        return new String[]{"COMPLETED", task.getTaskId(), resultUrl};
                    } else {
                        logger.warn("任务状态为成功但 resultUrl 为空，保持 PROCESSING: taskId={}", task.getTaskId());
                        taskStatusRepository.save(task);
                    }
                    return null;
                    
                case "failed":
                case "failure":
                case "error":
                    task.markAsFailed(errorMessage);
                    // 只在第一次记录失败日志，避免重复记录
                    if (loggedFailedTaskIds.add(task.getTaskId())) {
                        logger.warn("任务失败: taskId={}, error={}", task.getTaskId(), errorMessage);
                    }
                    taskStatusRepository.save(task);
                    // 返回任务信息，在事务外处理
                    return new String[]{"FAILED", task.getTaskId(), errorMessage};
                    
                case "processing":
                case "in_progress":
                case "not_start":
                case "pending":
                case "queued":
                    task.setStatus(TaskStatus.Status.PROCESSING);
                    logger.info("任务处理中: taskId={}, progress={}%", task.getTaskId(), progress);
                    break;
                    
                default:
                    logger.warn("未知任务状态: taskId={}, status={}", task.getTaskId(), status);
                    // 未知状态也检查是否超时
                    if (isTaskTimeout(task)) {
                        String timeoutError = "任务超时：外部API返回未知状态 " + status;
                        task.markAsFailed(timeoutError);
                        taskStatusRepository.save(task);
                        return new String[]{"FAILED", task.getTaskId(), timeoutError};
                    }
                    break;
            }
            
            taskStatusRepository.save(task);
            return null;
            
        } catch (Exception e) {
            logger.error("更新任务状态时发生错误: taskId={}, error={}", task.getTaskId(), e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 处理超时任务
     */
    @Transactional
    public void handleTimeoutTasks() {
        List<TaskStatus> timeoutTasks = taskStatusRepository.findTimeoutTasks();
        
        for (TaskStatus task : timeoutTasks) {
            task.markAsTimeout();
            taskStatusRepository.save(task);
            logger.warn("任务超时: taskId={}, pollCount={}", task.getTaskId(), task.getPollCount());
            
            // 同步更新业务表、UserWork 等，并记录错误日志
            try {
                taskQueueService.handleTaskFailureByTaskId(task.getTaskId(), "任务超时（轮询次数已达上限）");
            } catch (Exception e) {
                logger.error("处理超时任务失败: taskId={}, error={}", task.getTaskId(), e.getMessage());
            }
        }
        
        if (!timeoutTasks.isEmpty()) {
            logger.info("处理了 {} 个超时任务", timeoutTasks.size());
        }
    }
    
    /**
     * 创建或更新任务状态记录（避免重复创建）
     */
    @Transactional
    public TaskStatus createTaskStatus(String taskId, String username, CommonTaskType taskType, String externalTaskId) {
        // 先检查是否已存在
        Optional<TaskStatus> existingOpt = taskStatusRepository.findFirstByTaskIdOrderByIdDesc(taskId);
        if (existingOpt.isPresent()) {
            TaskStatus existing = existingOpt.get();
            // 如果已存在，更新 externalTaskId（如果提供了新的）
            if (externalTaskId != null && !externalTaskId.isEmpty()) {
                existing.setExternalTaskId(externalTaskId);
                existing.setUpdatedAt(LocalDateTime.now());
                logger.info("更新已存在的 TaskStatus: taskId={}, externalTaskId={}", taskId, externalTaskId);
                return taskStatusRepository.save(existing);
            }
            logger.info("TaskStatus 已存在，跳过创建: taskId={}", taskId);
            return existing;
        }
        
        // 不存在则创建新的
        TaskStatus taskStatus = new TaskStatus(taskId, username, taskType);
        taskStatus.setExternalTaskId(externalTaskId);
        taskStatus.setStatus(TaskStatus.Status.PROCESSING);
        taskStatus.setProgress(0);
        
        logger.info("创建新的 TaskStatus: taskId={}, externalTaskId={}", taskId, externalTaskId);
        return taskStatusRepository.save(taskStatus);
    }
    
    /**
     * 根据任务ID获取状态
     */
    public TaskStatus getTaskStatus(String taskId) {
        return taskStatusRepository.findFirstByTaskIdOrderByIdDesc(taskId).orElse(null);
    }
    
    /**
     * 获取用户的所有任务状态
     */
    public List<TaskStatus> getUserTaskStatuses(String username) {
        return taskStatusRepository.findByUsernameOrderByCreatedAtDesc(username);
    }
    
    /**
     * 取消任务
     */
    @Transactional
    public boolean cancelTask(String taskId, String username) {
        TaskStatus task = taskStatusRepository.findFirstByTaskIdOrderByIdDesc(taskId).orElse(null);

        if (task == null || !task.getUsername().equals(username)) {
            return false;
        }

        if (task.getStatus() == TaskStatus.Status.PROCESSING) {
            task.setStatus(TaskStatus.Status.CANCELLED);
            task.setUpdatedAt(LocalDateTime.now());
            taskStatusRepository.save(task);
            return true;
        }

        return false;
    }

    /**
     * 保存或更新任务状态
     */
    @Transactional
    public TaskStatus saveOrUpdateTaskStatus(TaskStatus taskStatus) {
        taskStatus.setUpdatedAt(LocalDateTime.now());
        return taskStatusRepository.save(taskStatus);
    }
    
    /**
     * 统一更新任务状态（触发级联）
     * 通过更新 task_status 表触发数据库触发器，自动级联更新其他表
     * 
     * @param taskId 任务ID
     * @param status 新状态
     * @param resultUrl 结果URL（可为null）
     * @param errorMessage 错误信息（可为null）
     * @return 是否更新成功
     */
    @Transactional
    public boolean updateTaskStatusWithCascade(String taskId, TaskStatus.Status status, String resultUrl, String errorMessage) {
        // 使用 findFirst 处理可能的重复记录
        TaskStatus taskStatus = taskStatusRepository.findFirstByTaskIdOrderByIdDesc(taskId).orElse(null);
        if (taskStatus == null) {
            logger.warn("任务状态记录不存在，无法触发级联更新: taskId={}", taskId);
            return false;
        }
        
        // 只有状态变化时才更新task_status表
        boolean statusChanged = taskStatus.getStatus() != status;
        if (statusChanged) {
            taskStatus.setStatus(status);
            taskStatus.setUpdatedAt(LocalDateTime.now());
            
            if (resultUrl != null) {
                taskStatus.setResultUrl(resultUrl);
            }
            
            if (errorMessage != null) {
                taskStatus.setErrorMessage(errorMessage);
            }
            
            if (status == TaskStatus.Status.COMPLETED) {
                taskStatus.setProgress(100);
                taskStatus.setCompletedAt(LocalDateTime.now());
            }
            
            taskStatusRepository.save(taskStatus);
            logger.info("任务状态已更新: taskId={}, status={}", taskId, status);
        }
        
        // 无论状态是否变化，都要确保业务表同步（防止业务表状态不一致）
        syncBusinessTableStatus(taskId, status, resultUrl, errorMessage);
        
        return true;
    }
    
    /**
     * 同步业务表状态
     */
    private void syncBusinessTableStatus(String taskId, TaskStatus.Status status, String resultUrl, String errorMessage) {
        if (taskId == null) return;
        
        if (taskId.startsWith("sb_") || taskId.startsWith("storyboard_")) {
            // 同步分镜视频任务
            try {
                storyboardVideoTaskRepository.findByTaskId(taskId).ifPresent(task -> {
                    com.example.demo.model.StoryboardVideoTask.TaskStatus newTaskStatus = 
                        convertToStoryboardTaskStatus(status);
                    if (task.getStatus() != newTaskStatus) {
                        task.setStatus(newTaskStatus);
                        task.setUpdatedAt(LocalDateTime.now());
                        if (errorMessage != null) {
                            task.setErrorMessage(errorMessage);
                        }
                        if (resultUrl != null) {
                            task.setResultUrl(resultUrl);
                            // 如果是视频URL（不是Base64图片），同时设置videoUrls
                            if (status == TaskStatus.Status.COMPLETED && !resultUrl.startsWith("data:image")) {
                                task.setVideoUrls("[\"" + resultUrl + "\"]");
                                logger.info("已设置videoUrls: taskId={}", taskId);
                            }
                        }
                        if (status == TaskStatus.Status.COMPLETED) {
                            task.setProgress(100);
                            task.setCompletedAt(LocalDateTime.now());
                        } else if (status == TaskStatus.Status.FAILED) {
                            task.setCompletedAt(LocalDateTime.now());
                        }
                        storyboardVideoTaskRepository.save(task);
                        logger.info("已同步 StoryboardVideoTask 状态: taskId={}, status={}", taskId, newTaskStatus);
                    }
                });
            } catch (Exception e) {
                logger.warn("同步 StoryboardVideoTask 状态失败: taskId={}, error={}", taskId, e.getMessage());
            }
        } else if (taskId.startsWith("img2vid_")) {
            // 同步图生视频任务
            try {
                imageToVideoTaskRepository.findByTaskId(taskId).ifPresent(task -> {
                    com.example.demo.model.ImageToVideoTask.TaskStatus newTaskStatus = 
                        convertToImageToVideoTaskStatus(status);
                    if (task.getStatus() != newTaskStatus) {
                        task.updateStatus(newTaskStatus);
                        task.setUpdatedAt(LocalDateTime.now());
                        if (errorMessage != null) {
                            task.setErrorMessage(errorMessage);
                        }
                        if (resultUrl != null) {
                            task.setResultUrl(resultUrl);
                        }
                        if (status == TaskStatus.Status.COMPLETED) {
                            task.setProgress(100);
                            task.setCompletedAt(LocalDateTime.now());
                        } else if (status == TaskStatus.Status.FAILED) {
                            task.setCompletedAt(LocalDateTime.now());
                        }
                        imageToVideoTaskRepository.save(task);
                        logger.info("已同步 ImageToVideoTask 状态: taskId={}, status={}", taskId, newTaskStatus);
                    }
                });
            } catch (Exception e) {
                logger.warn("同步 ImageToVideoTask 状态失败: taskId={}, error={}", taskId, e.getMessage());
            }
        } else if (taskId.startsWith("txt2vid_")) {
            // 同步文生视频任务
            try {
                textToVideoTaskRepository.findByTaskId(taskId).ifPresent(task -> {
                    com.example.demo.model.TextToVideoTask.TaskStatus newTaskStatus = 
                        convertToTextToVideoTaskStatus(status);
                    if (task.getStatus() != newTaskStatus) {
                        task.updateStatus(newTaskStatus);
                        task.setUpdatedAt(LocalDateTime.now());
                        if (errorMessage != null) {
                            task.setErrorMessage(errorMessage);
                        }
                        if (resultUrl != null) {
                            task.setResultUrl(resultUrl);
                        }
                        if (status == TaskStatus.Status.COMPLETED) {
                            task.setProgress(100);
                            task.setCompletedAt(LocalDateTime.now());
                        } else if (status == TaskStatus.Status.FAILED) {
                            task.setCompletedAt(LocalDateTime.now());
                        }
                        textToVideoTaskRepository.save(task);
                        logger.info("已同步 TextToVideoTask 状态: taskId={}, status={}", taskId, newTaskStatus);
                    }
                });
            } catch (Exception e) {
                logger.warn("同步 TextToVideoTask 状态失败: taskId={}, error={}", taskId, e.getMessage());
            }
        }
        
        // 如果是失败状态，返还冻结的积分并记录错误日志
        if (status == TaskStatus.Status.FAILED) {
            // 返还冻结的积分
            try {
                if (taskId.startsWith("sb_") || taskId.startsWith("storyboard_")) {
                    // 分镜任务需要根据失败阶段返还对应的积分
                    // 检查任务状态，判断失败在哪个阶段
                    StoryboardVideoTask storyboardTask = storyboardVideoTaskRepository.findByTaskId(taskId).orElse(null);
                    
                    if (storyboardTask != null) {
                        String storyboardResultUrl = storyboardTask.getResultUrl();
                        String videoTaskIds = storyboardTask.getVideoTaskIds();
                        
                        // 判断失败阶段：
                        // 1. 如果没有 resultUrl（分镜图），说明失败在分镜图生成阶段，只返还 _img
                        // 2. 如果有 resultUrl 但没有 videoTaskIds，说明只生成了分镜图，未开始视频生成，只返还 _img
                        // 3. 如果有 videoTaskIds，说明失败在视频生成阶段，只返还 _vid
                        
                        boolean hasStoryboard = (storyboardResultUrl != null && !storyboardResultUrl.isEmpty());
                        boolean hasVideoTask = (videoTaskIds != null && !videoTaskIds.isEmpty() && !"[]".equals(videoTaskIds));
                        
                        if (!hasStoryboard) {
                            // 分镜图生成阶段失败，只返还 _img 积分
                            try {
                                userService.returnFrozenPoints(taskId + "_img");
                                logger.info("级联更新时已返还分镜图积分（分镜图阶段失败）: taskId={}_img", taskId);
                            } catch (Exception e) {
                                logger.debug("级联更新时分镜图积分返还失败（可能未冻结或已返还）: taskId={}_img", taskId);
                            }
                        } else if (hasVideoTask) {
                            // 视频生成阶段失败，只返还 _vid 积分
                            try {
                                userService.returnFrozenPoints(taskId + "_vid");
                                logger.info("级联更新时已返还分镜视频积分（视频生成阶段失败）: taskId={}_vid", taskId);
                            } catch (Exception e) {
                                logger.debug("级联更新时分镜视频积分返还失败（可能未冻结或已返还）: taskId={}_vid", taskId);
                            }
                        } else {
                            // 只生成了分镜图但未开始视频生成，只返还 _img 积分
                            try {
                                userService.returnFrozenPoints(taskId + "_img");
                                logger.info("级联更新时已返还分镜图积分（未开始视频生成）: taskId={}_img", taskId);
                            } catch (Exception e) {
                                logger.debug("级联更新时分镜图积分返还失败（可能未冻结或已返还）: taskId={}_img", taskId);
                            }
                        }
                    } else {
                        // 找不到任务记录，尝试返还两个阶段的积分（兜底逻辑）
                        logger.warn("找不到分镜任务记录，尝试返还所有积分: taskId={}", taskId);
                        try {
                            userService.returnFrozenPoints(taskId + "_vid");
                        } catch (Exception e) {
                            logger.debug("返还 _vid 积分失败: taskId={}", taskId);
                        }
                        try {
                            userService.returnFrozenPoints(taskId + "_img");
                        } catch (Exception e) {
                            logger.debug("返还 _img 积分失败: taskId={}", taskId);
                        }
                    }
                } else {
                    // 其他任务类型直接使用 taskId
                    userService.returnFrozenPoints(taskId);
                    logger.info("级联更新时已返还积分: taskId={}", taskId);
                }
            } catch (Exception e) {
                logger.debug("级联更新时积分返还失败（可能未冻结或已返还）: taskId={}", taskId);
            }
            
            // 记录错误日志
            if (errorMessage != null) {
                try {
                    String username = null;
                    String taskType = "UNKNOWN";
                    
                    if (taskId.startsWith("img2vid_")) {
                        taskType = "IMAGE_TO_VIDEO";
                        username = imageToVideoTaskRepository.findByTaskId(taskId)
                            .map(t -> t.getUsername()).orElse(null);
                    } else if (taskId.startsWith("storyboard_") || taskId.startsWith("sb_")) {
                        taskType = "STORYBOARD_VIDEO";
                        username = storyboardVideoTaskRepository.findByTaskId(taskId)
                            .map(t -> t.getUsername()).orElse(null);
                    } else if (taskId.startsWith("txt2vid_")) {
                        taskType = "TEXT_TO_VIDEO";
                        username = textToVideoTaskRepository.findByTaskId(taskId)
                            .map(t -> t.getUsername()).orElse(null);
                    }
                    
                    if (username != null) {
                        userErrorLogService.logErrorAsync(
                            username,
                            com.example.demo.model.UserErrorLog.ErrorType.TASK_PROCESSING_ERROR,
                            errorMessage,
                            "TaskStatusPollingService.updateTaskStatusWithCascade",
                            taskId,
                            taskType
                        );
                    } else {
                        logger.warn("无法记录错误日志，未找到用户名: taskId={}", taskId);
                    }
                } catch (Exception logException) {
                    logger.warn("记录错误日志失败: taskId={}, error={}", taskId, logException.getMessage());
                }
            }
        }
        
        // 同步 UserWork 状态
        try {
            UserWork.WorkStatus workStatus = convertToUserWorkStatus(status);
            userWorkService.updateWorkStatusWithResult(taskId, workStatus, resultUrl);
            logger.info("已同步 UserWork 状态: taskId={}, status={}", taskId, workStatus);
        } catch (Exception e) {
            logger.warn("同步 UserWork 状态失败: taskId={}, error={}", taskId, e.getMessage());
        }
    }
    
    /**
     * 将 TaskStatus.Status 转换为 UserWork.WorkStatus
     */
    private UserWork.WorkStatus convertToUserWorkStatus(TaskStatus.Status status) {
        return switch (status) {
            case PENDING -> UserWork.WorkStatus.PENDING;
            case PROCESSING -> UserWork.WorkStatus.PROCESSING;
            case COMPLETED -> UserWork.WorkStatus.COMPLETED;
            case FAILED -> UserWork.WorkStatus.FAILED;
            default -> UserWork.WorkStatus.PROCESSING;
        };
    }
    
    /**
     * 将 TaskStatus.Status 转换为 StoryboardVideoTask.TaskStatus
     */
    private com.example.demo.model.StoryboardVideoTask.TaskStatus convertToStoryboardTaskStatus(TaskStatus.Status status) {
        return switch (status) {
            case PENDING -> com.example.demo.model.StoryboardVideoTask.TaskStatus.PENDING;
            case PROCESSING -> com.example.demo.model.StoryboardVideoTask.TaskStatus.PROCESSING;
            case COMPLETED -> com.example.demo.model.StoryboardVideoTask.TaskStatus.COMPLETED;
            case FAILED -> com.example.demo.model.StoryboardVideoTask.TaskStatus.FAILED;
            default -> com.example.demo.model.StoryboardVideoTask.TaskStatus.PROCESSING;
        };
    }
    
    /**
     * 将 TaskStatus.Status 转换为 ImageToVideoTask.TaskStatus
     */
    private com.example.demo.model.ImageToVideoTask.TaskStatus convertToImageToVideoTaskStatus(TaskStatus.Status status) {
        return switch (status) {
            case PENDING -> com.example.demo.model.ImageToVideoTask.TaskStatus.PENDING;
            case PROCESSING -> com.example.demo.model.ImageToVideoTask.TaskStatus.PROCESSING;
            case COMPLETED -> com.example.demo.model.ImageToVideoTask.TaskStatus.COMPLETED;
            case FAILED -> com.example.demo.model.ImageToVideoTask.TaskStatus.FAILED;
            default -> com.example.demo.model.ImageToVideoTask.TaskStatus.PROCESSING;
        };
    }
    
    /**
     * 将 TaskStatus.Status 转换为 TextToVideoTask.TaskStatus
     */
    private com.example.demo.model.TextToVideoTask.TaskStatus convertToTextToVideoTaskStatus(TaskStatus.Status status) {
        return switch (status) {
            case PENDING -> com.example.demo.model.TextToVideoTask.TaskStatus.PENDING;
            case PROCESSING -> com.example.demo.model.TextToVideoTask.TaskStatus.PROCESSING;
            case COMPLETED -> com.example.demo.model.TextToVideoTask.TaskStatus.COMPLETED;
            case FAILED -> com.example.demo.model.TextToVideoTask.TaskStatus.FAILED;
            default -> com.example.demo.model.TextToVideoTask.TaskStatus.PROCESSING;
        };
    }
    
    /**
     * 标记任务为完成状态（触发级联）
     */
    @Transactional
    public boolean markTaskCompleted(String taskId, String resultUrl) {
        return updateTaskStatusWithCascade(taskId, TaskStatus.Status.COMPLETED, resultUrl, null);
    }
    
    /**
     * 标记任务为失败状态（触发级联）
     */
    @Transactional
    public boolean markTaskFailed(String taskId, String errorMessage) {
        return updateTaskStatusWithCascade(taskId, TaskStatus.Status.FAILED, null, errorMessage);
    }
    
    /**
     * 标记任务为处理中状态（触发级联）
     */
    @Transactional
    public boolean markTaskProcessing(String taskId) {
        return updateTaskStatusWithCascade(taskId, TaskStatus.Status.PROCESSING, null, null);
    }
    
    /**
     * 解析进度字符串（如 "100%"）为整数
     */
    private int parseProgress(String progressStr) {
        if (progressStr == null || progressStr.isEmpty()) {
            return 0;
        }
        try {
            // 移除百分号并解析
            String numStr = progressStr.replace("%", "").trim();
            return Integer.parseInt(numStr);
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}

