package com.dora.service.impl;

import com.dora.dto.CreateTaskDto;
import com.dora.dto.AiTaskWithPlazaDto;
import com.dora.dto.api.ApiResponse;
import com.dora.dto.api.Choice;
import com.dora.dto.api.Message;
import com.dora.entity.AiTask;
import com.dora.entity.PointsConfig;
import com.dora.exception.InsufficientPointsException;
import com.dora.mapper.AiTaskMapper;
import com.dora.mapper.PointsConfigMapper;
import com.dora.service.AiTaskService;
import com.dora.service.AsyncTaskExecutor;
import com.dora.service.PointsService;
import com.dora.service.QueueService;
import com.dora.service.NotificationService;
import com.dora.service.PlazaService;
import com.dora.mapper.PlazaWorkMapper;
import com.dora.dto.TaskProgressDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
@RequiredArgsConstructor
public class AiTaskServiceImpl implements AiTaskService {

    private final AiTaskMapper aiTaskMapper;
    private final PointsConfigMapper pointsConfigMapper;
    private final PointsService pointsService;
    private final QueueService queueService;
    private final AsyncTaskExecutor asyncTaskExecutor;
    private final NotificationService notificationService;
    private final com.dora.service.AIProviderService aiProviderService;
    private final com.dora.service.RunningHubQueueService runningHubQueueService;
    private final com.dora.service.ThirdPartyApiService thirdPartyApiService;
    private final PlazaService plazaService;
    private final PlazaWorkMapper plazaWorkMapper;

    private static final Pattern URL_PATTERN = Pattern.compile("!\\[.*?\\]\\((https?://[^)]+)\\)");

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AiTask createTask(CreateTaskDto createTaskDto) throws InsufficientPointsException, IllegalArgumentException {
        // 1. 验证模型并获取价格
        PointsConfig pointsConfig = pointsConfigMapper.findByModelName(createTaskDto.getModelName());
        if (pointsConfig == null || pointsConfig.getIsEnabled() == 0) {
            throw new IllegalArgumentException("模型不存在或已禁用: " + createTaskDto.getModelName());
        }
        Integer cost = pointsConfig.getPointsCost();
        String taskNo = generateTaskNo(); // 保证任务编号唯一

        // 2. 扣除积分 (即“冻结”操作)
        pointsService.deductPoints(
                createTaskDto.getUserId(),
                cost,
                taskNo,
                "AI任务创建: " + createTaskDto.getModelName()
        );

        // 3. 创建并持久化任务
        AiTask task = new AiTask();
        task.setTaskNo(taskNo);
        task.setUserId(createTaskDto.getUserId());
        task.setModelName(createTaskDto.getModelName());
        task.setPrompt(createTaskDto.getPrompt());
        task.setImageUrl(createTaskDto.getImageUrl());
        task.setImageBase64(createTaskDto.getImageBase64());
        task.setAspectRatio(createTaskDto.getAspectRatio());
        task.setPointsFrozen(cost);
        task.setStatus("created");
        task.setTaskType(pointsConfig.getTaskType() != null ? pointsConfig.getTaskType() : "other");
        task.setProviderType(pointsConfig.getProviderType());  // 设置provider类型

        // 如果是续作任务，将 sourcePid 暂存到 providerResponse 中（JSON格式），供 Executor 使用
        if (createTaskDto.getSourcePid() != null) {
            task.setProviderResponse("{\"tempSourcePid\":\"" + createTaskDto.getSourcePid() + "\"}");
        }

        aiTaskMapper.insert(task);

        // 4. 判断provider类型，选择不同的处理流程
        String providerType = pointsConfig.getProviderType();
        if ("runninghub".equals(providerType)) {
            // RunningHub：使用队列服务管理并发
            boolean submitted = runningHubQueueService.enqueueOrSubmit(task);
            if (submitted) {
                log.info("RunningHub任务 {} 立即提交", task.getTaskNo());
            } else {
                log.info("RunningHub任务 {} 加入等待队列，队列长度: {}", 
                         task.getTaskNo(), runningHubQueueService.getWaitingQueueSize());
            }
        } else if ("suchuang".equals(providerType)) {
            // 速创：异步Provider，立即处理，不进入队列
            log.info("速创任务 {} 立即处理（异步）", task.getTaskNo());
            processTask(task.getTaskNo());
        } else {
            // OpenAI等其他：加入队列，由原有流程处理（同步）
            queueService.enqueue(task.getModelName(), task.getTaskNo());
            updateTaskStatus(task.getTaskNo(), "queued", "任务已进入等待队列。");
        }

        return aiTaskMapper.findByTaskNo(task.getTaskNo());
    }

    /**
     * 标记任务为失败
     */
    private void markTaskFailed(String taskNo, String errorMessage) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task != null) {
            task.setStatus("failed");
            task.setErrorMessage(errorMessage);
            task.setCompleteTime(LocalDateTime.now());
            task.setUpdateTime(LocalDateTime.now());
            aiTaskMapper.update(task);
            
            // 发送通知
            notificationService.notifyTaskFailed(task.getUserId(), taskNo, errorMessage);
        }
    }

    @Override
    public AiTask getTaskByTaskNo(String taskNo, Long userId) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        // 安全校验：如果传入了userId，则确保用户只能查询自己的任务
        if (userId != null && task != null && !task.getUserId().equals(userId)) {
            return null; // 用户无权访问此任务
        }
        return task;
    }

    @Override
    public List<AiTask> getUserTasks(Long userId, String status) {
        return aiTaskMapper.findUserTasks(userId, status);
    }

    @Override
    public List<AiTask> getUserTasksWithType(Long userId, String status, String taskType) {
        return aiTaskMapper.findUserTasksWithType(userId, status, taskType);
    }

    @Override
    public List<AiTaskWithPlazaDto> getUserTasksWithPlaza(Long userId, String status) {
        return aiTaskMapper.findUserTasksWithPlaza(userId, status);
    }

    @Override
    public List<AiTaskWithPlazaDto> getUserTasksWithPlazaAndType(Long userId, String status, String taskType) {
        return aiTaskMapper.findUserTasksWithPlazaAndType(userId, status, taskType);
    }

    @Override
    public List<AiTask> getAllTasks(Long userId, String status, String modelName, String taskNo) {
        return aiTaskMapper.findAllAdmin(userId, status, modelName, taskNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelTask(String taskNo) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task == null) {
            return false;
        }

        // 只有排队中的任务可以被安全取消
        if ("queued".equals(task.getStatus())) {
            // 1. 从 Redis 队列中移除任务
            long removed = queueService.removeFromQueue(task.getModelName(), taskNo);
            if (removed > 0) {
                log.info("任务 {} 已从队列中移除，模型: {}", taskNo, task.getModelName());
            } else {
                log.warn("任务 {} 不在队列中，可能已被处理或不存在，模型: {}", taskNo, task.getModelName());
            }
            
            // 2. 更新任务状态
            task.setStatus("cancelled");
            task.setErrorMessage("由管理员手动取消。");
            task.setCompleteTime(LocalDateTime.now());
            aiTaskMapper.update(task);

            // 3. 退还积分
            pointsService.refundPoints(
                    task.getUserId(),
                    task.getPointsFrozen(),
                    taskNo,
                    "管理员取消任务，退还积分。"
            );
            
            log.info("任务 {} 取消成功，已退还积分: {}", taskNo, task.getPointsFrozen());
            return true;
        }
        // 对于正在处理中的任务，取消操作比较复杂，可能需要与第三方API交互
        // 此处暂时只支持取消排队任务
        log.warn("尝试取消一个非排队中状态的任务: {} (状态: {})", taskNo, task.getStatus());
        return false;
    }

    @Override
    public void processTask(String taskNo) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task == null) {
            log.warn("任务 {} 不存在，无法处理。", taskNo);
            return;
        }
        
        // 允许处理 created 或 queued 状态的任务
        // created: 速创/RunningHub任务立即处理
        // queued: 从队列中取出的任务
        if (!"created".equals(task.getStatus()) && !"queued".equals(task.getStatus())) {
            log.warn("任务 {} 状态不正确 (status={})，无法处理。", taskNo, task.getStatus());
            if ("queued".equals(task.getStatus())) {
                // 只有queued状态的任务才需要释放队列槽位
                queueService.decrementProcessingCount(task.getModelName());
            }
            return;
        }

        // 1. 更新状态为"处理中"并发送通知
        updateAndNotify(task, "processing", "AI模型正在生成内容...", null);

        // 2. 根据Provider类型选择处理方式
        String providerType = task.getProviderType();
        if ("runninghub".equals(providerType) || "suchuang".equals(providerType)) {
            // 异步Provider：使用AsyncTaskExecutor
            asyncTaskExecutor.executeApiCall(task).whenComplete((apiResponse, throwable) -> {
                handleTaskCompletion(task, apiResponse, throwable, taskNo);
            });
        } else {
            // 同步Provider（OpenAI等）：直接调用ThirdPartyApiService
            handleSyncProviderTask(task, taskNo);
        }
    }

    private void handleSyncProviderTask(AiTask task, String taskNo) {
        boolean shouldReleaseSlot = true;
        try {
            // 调用同步API
            com.dora.dto.api.ApiResponse apiResponse = thirdPartyApiService.executeGenerationForTask(task);
            
            if (apiResponse != null && apiResponse.getChoices() != null && !apiResponse.getChoices().isEmpty()) {
                // 成功：从choices中提取结果URL
                Optional<String> resultUrlOpt = extractUrlFromResponse(apiResponse);
                if (resultUrlOpt.isPresent()) {
                    updateAndNotify(task, "completed", "生成完成", resultUrlOpt.get());
                    log.info("任务 {} 处理完成", taskNo);
                } else {
                    markTaskAsFailed(taskNo, "API响应中未找到结果URL");
                    log.warn("任务 {} 处理失败: API响应中未找到结果URL", taskNo);
                }
            } else {
                // 失败：标记任务失败
                String errorMsg = "API调用失败或返回空结果";
                markTaskAsFailed(taskNo, errorMsg);
                log.warn("任务 {} 处理失败: {}", taskNo, errorMsg);
            }
        } catch (Exception e) {
            log.error("任务 {} 处理异常", taskNo, e);
            markTaskAsFailed(taskNo, "处理异常: " + e.getMessage());
        } finally {
            if (shouldReleaseSlot) {
                queueService.decrementProcessingCount(task.getModelName());
                log.debug("释放处理槽位 - 模型: {}, 任务: {}", task.getModelName(), taskNo);
            }
        }
    }

    private void handleTaskCompletion(AiTask task, com.dora.dto.api.ApiResponse apiResponse, Throwable throwable, String taskNo) {
        boolean shouldReleaseSlot = true;
        try {
            if (throwable != null) {
                // 异常情况：API调用失败或发生未知错误
                log.error("任务 {} 处理失败。", taskNo, throwable);
                markTaskAsFailed(taskNo, "处理失败: " + throwable.getMessage());
            } else {
                // 正常情况：处理API响应
                handleApiResponse(task, apiResponse);
                
                // 检查是否是异步Provider：如果是，不释放槽位（等轮询完成后释放）
                if (apiResponse.getId() != null && !apiResponse.getId().trim().isEmpty()) {
                    shouldReleaseSlot = false;
                    log.info("异步任务 {} 已提交，保持处理槽位直到轮询完成", taskNo);
                }
            }
        } finally {
            // 3. 只有同步Provider或失败的任务才立即释放处理槽位
            if (shouldReleaseSlot) {
                queueService.decrementProcessingCount(task.getModelName());
                log.info("任务 {} 处理完毕，已释放模型 {} 的一个处理槽位。", taskNo, task.getModelName());
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTaskStatus(String taskNo, String newStatus, String message) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task != null) {
            task.setStatus(newStatus);
            task.setProgressMessage(message);
            if(newStatus.equals("processing")){
                task.setStartTime(LocalDateTime.now());
            } else if (newStatus.equals("queued")) {
                task.setQueueTime(LocalDateTime.now());
            }
            aiTaskMapper.update(task);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markTaskAsSuccess(String taskNo, String resultUrl) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task != null) {
            updateAndNotify(task, "completed", "任务已成功完成。", resultUrl);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markTaskAsFailed(String taskNo, String errorMessage) {
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task != null && !"failed".equals(task.getStatus())) {
            updateAndNotify(task, "failed", errorMessage, null);

            pointsService.refundPoints(
                    task.getUserId(),
                    task.getPointsFrozen(),
                    taskNo,
                    "任务失败，退还积分"
            );
        }
    }

    private void handleApiResponse(AiTask task, ApiResponse apiResponse) {
        try {
            // 检查是否是异步Provider的响应（包含taskId）
            if (apiResponse.getId() != null && !apiResponse.getId().trim().isEmpty()) {
                // 异步Provider：保存providerTaskId，状态保持processing，等待轮询
                log.info("异步任务 {} 已提交，Provider任务ID: {}", task.getTaskNo(), apiResponse.getId());
                
                // 更新任务的providerTaskId
                task.setProviderTaskId(apiResponse.getId());
                task.setStatus("processing");
                task.setProgressMessage("任务已提交到AI服务商，正在处理中...");
                task.setUpdateTime(LocalDateTime.now());
                aiTaskMapper.update(task);
                
                // 发送WebSocket通知
                notificationService.notifyTaskProgress(task.getUserId(), task.getTaskNo(), 
                    "processing", 20, "任务已提交到AI服务商，正在处理中...");
                
                log.info("异步任务 {} 状态已更新，等待轮询获取结果", task.getTaskNo());
                return;
            }
            
            // 同步Provider：直接解析结果URL
            String resultUrl = extractUrlFromResponse(apiResponse)
                    .orElseThrow(() -> new RuntimeException("在API响应中未找到有效的结果URL。"));
            markTaskAsSuccess(task.getTaskNo(), resultUrl);
            
        } catch (Exception e) {
            log.error("处理任务 {} 的API响应失败。", task.getTaskNo(), e);
            markTaskAsFailed(task.getTaskNo(), "处理API响应失败: " + e.getMessage());
        }
    }

    private Optional<String> extractUrlFromResponse(ApiResponse response) {
        if (response == null || response.getChoices() == null || response.getChoices().isEmpty()) {
            return Optional.empty();
        }
        return response.getChoices().stream()
                .findFirst()
                .map(Choice::getMessage)
                .map(Message::getContent)
                .flatMap(this::findUrlInContent);
    }

    private Optional<String> findUrlInContent(String content) {
        if (content == null) {
            return Optional.empty();
        }
        Matcher matcher = URL_PATTERN.matcher(content);
        return matcher.find() ? Optional.of(matcher.group(1)) : Optional.empty();
    }

    private String generateTaskNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        int randomNum = ThreadLocalRandom.current().nextInt(1000, 10000);
        return "TASK-" + timestamp + "-" + randomNum;
    }


    private void updateAndNotify(AiTask task, String status, String message, String resultUrl) {
        task.setStatus(status);
        task.setProgressMessage(message);
        if ("processing".equals(status)) {
            task.setStartTime(LocalDateTime.now());
            task.setProgress(10); // Set initial progress
        } else if ("completed".equals(status)) {
            task.setCompleteTime(LocalDateTime.now());
            task.setProgress(100);
            task.setResultUrl(resultUrl);
            task.setPointsConsumed(task.getPointsFrozen());
        } else if ("failed".equals(status)) {
            task.setCompleteTime(LocalDateTime.now());
            task.setErrorMessage(message);
        }
        aiTaskMapper.update(task);

        TaskProgressDto progressDto = TaskProgressDto.builder()
                .taskNo(task.getTaskNo())
                .status(task.getStatus())
                .progress(task.getProgress())
                .message(task.getProgressMessage())
                .resultUrl(task.getResultUrl())
                .errorMessage(task.getErrorMessage())
                .build();
        
        notificationService.sendTaskUpdateToUser(task.getUserId(), progressDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUserTask(String taskNo, Long userId) {
        log.info("用户 {} 尝试删除AI任务 {}", userId, taskNo);
        
        // 1. 验证任务存在且属于该用户
        AiTask task = aiTaskMapper.findByTaskNo(taskNo);
        if (task == null || !task.getUserId().equals(userId)) {
            log.warn("任务不存在或无权删除，taskNo: {}, userId: {}", taskNo, userId);
            return false;
        }
        
        // 2. 检查任务状态，正在处理中的任务不允许删除
        if ("processing".equals(task.getStatus())) {
            log.warn("任务正在处理中，无法删除，taskNo: {}, status: {}", taskNo, task.getStatus());
            return false;
        }
        
        try {
            // 3. 删除AI任务（逻辑删除）
            int deletedTasks = aiTaskMapper.deleteByTaskNoAndUserId(taskNo, userId);
            if (deletedTasks == 0) {
                log.warn("删除AI任务失败，taskNo: {}, userId: {}", taskNo, userId);
                return false;
            }
            
            // 4. 删除相关的广场作品（如果存在）
            try {
                // 通过taskNo查找对应的广场作品并删除
                com.dora.entity.PlazaWork plazaWork = plazaWorkMapper.findByTaskNo(taskNo);
                if (plazaWork != null && plazaWork.getUserId().equals(userId)) {
                    plazaService.deleteWork(userId, plazaWork.getWorkNo());
                    log.info("已删除相关广场作品，workNo: {}", plazaWork.getWorkNo());
                }
            } catch (Exception e) {
                log.warn("删除相关广场作品时发生异常，但AI任务删除成功，taskNo: {}", taskNo, e);
                // 广场作品删除失败不影响AI任务删除的成功
            }
            
            // 5. 删除任务时不退还积分
            // 无论任务状态如何，删除时都不退还积分
            log.info("任务删除完成，不退还积分，taskNo: {}, frozenPoints: {}", taskNo, task.getPointsFrozen());
            
            log.info("AI任务删除成功，taskNo: {}, userId: {}", taskNo, userId);
            return true;
            
        } catch (Exception e) {
            log.error("删除AI任务时发生异常，taskNo: {}, userId: {}", taskNo, userId, e);
            throw e; // 重新抛出异常，触发事务回滚
        }
    }
}
