package com.dora.controller;

import com.dora.common.Result;
import com.dora.dto.CreateTaskDto;
import com.dora.dto.TaskSubmitRequest;
import com.dora.dto.TaskSubmitResponse;
import com.dora.dto.AiTaskWithPlazaDto;
import com.dora.entity.AiTask;
import com.dora.exception.InsufficientPointsException;
import com.dora.service.AiTaskService;
import com.dora.service.QueueService;
import com.dora.service.PlazaService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.dora.dto.AiTaskDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户端 - AI任务管理控制器
 * 
 * 提供以下功能：
 * 1. 提交AI生成任务（图片/视频）
 * 2. 查询任务进度和结果
 * 3. 查看用户的任务历史
 * 
 * @author 1818AI
 * @since 2025-10-19
 */
@Slf4j
@RestController
@RequestMapping("/user/ai/tasks")
@Tag(name = "AI任务管理", description = "用户端API - 用于创建和管理AI生成任务（图片、视频等）")
@RequiredArgsConstructor
public class AiTaskController {

    private final AiTaskService aiTaskService;
    private final QueueService queueService;
    private final PlazaService plazaService;

    /**
     * 提交AI生成任务
     * 
     * @param request 任务提交请求（包含模型名称和提示词）
     * @return 任务提交结果（包含任务编号、状态、队列位置等）
     */
    @PostMapping("/submit")
    @Operation(
        summary = "提交一个新的AI任务", 
        description = "创建一个新的AI生成任务（图片或视频），系统会自动扣除对应的积分并将任务放入队列。" +
                      "任务提交成功后，可通过返回的任务编号查询进度。\n\n" +
                      "**认证方式**：\n" +
                      "- JWT Token（Web端）：在登录后自动使用\n" +
                      "- API Key（开发者）：在请求头添加 `Authorization: Bearer {your_api_key}`\n\n" +
                      "**图生视频**：\n" +
                      "- 提供 `imageUrl` 或 `imageBase64` 参数即可实现图生视频\n" +
                      "- 两种方式二选一，优先使用 `imageUrl`"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "任务提交成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误 - 模型不存在或提示词无效"),
            @ApiResponse(responseCode = "401", description = "未认证 - 请提供JWT Token或API Key"),
            @ApiResponse(responseCode = "402", description = "积分不足 - 请先充值")
    })
    public Result<TaskSubmitResponse> submitTask(
            @Parameter(description = "任务提交请求，包含模型名称、提示词和可选的图片参数", required = true)
            @RequestBody TaskSubmitRequest request) {
        try {
            // 从Spring Security上下文获取当前用户ID（支持JWT和API Key两种方式）
            Long currentUserId = com.dora.util.SecurityUtil.getCurrentUserId();

            log.info("用户 {} 提交AI任务，模型: {}, 提示词长度: {}, 是否图生视频: {}", 
                     currentUserId, request.getModelName(), request.getPrompt().length(), 
                     request.isImageToVideo());

            CreateTaskDto.CreateTaskDtoBuilder builder = CreateTaskDto.builder()
                    .userId(currentUserId)
                    .modelName(request.getModelName())
                    .prompt(request.getPrompt())
                    .imageUrl(request.getImageUrl())
                    .imageBase64(request.getImageBase64())
                    .aspectRatio(request.getAspectRatio());

            // 处理续作逻辑
            if (request.getSourceTaskNo() != null && !request.getSourceTaskNo().trim().isEmpty()) {
                AiTask sourceTask = aiTaskService.getTaskByTaskNo(request.getSourceTaskNo(), currentUserId);
                if (sourceTask != null) {
                    // 校验原任务是否支持续作（必须是视频任务且有 providerPid）
                    // 支持的任务类型：text_to_video（文生视频）、image_to_video（图生视频）
                    boolean isVideoTask = "text_to_video".equals(sourceTask.getTaskType()) || 
                                         "image_to_video".equals(sourceTask.getTaskType());
                    if (isVideoTask && sourceTask.getProviderPid() != null && !sourceTask.getProviderPid().isEmpty()) {
                        builder.sourcePid(sourceTask.getProviderPid());
                        log.info("续作任务，来源任务: {}, 类型: {}, PID: {}", 
                                sourceTask.getTaskNo(), sourceTask.getTaskType(), sourceTask.getProviderPid());
                    } else {
                        log.warn("续作失败：原任务 {} 不支持续作 (type={}, pid={})", 
                                request.getSourceTaskNo(), sourceTask.getTaskType(), sourceTask.getProviderPid());
                    }
                } else {
                    log.warn("续作失败：找不到原任务 {} 或无权访问", request.getSourceTaskNo());
                }
            }

            CreateTaskDto createTaskDto = builder.build();

            AiTask createdTask = aiTaskService.createTask(createTaskDto);

            // 获取队列信息以提供即时反馈
            long queuePosition = queueService.getQueueLength(createdTask.getModelName());
            int estimatedWaitTime = calculateEstimatedWaitTime(queuePosition);

            TaskSubmitResponse response = new TaskSubmitResponse(
                    createdTask.getTaskNo(),
                    createdTask.getStatus(),
                    queuePosition,
                    estimatedWaitTime,
                    "任务创建成功，请通过任务编号查询进度"
            );

            log.info("任务创建成功，taskNo: {}, 队列位置: {}", createdTask.getTaskNo(), queuePosition);

            return Result.success(response, "任务提交成功");

        } catch (com.dora.exception.AuthenticationException e) {
            log.warn("用户未认证: {}", e.getMessage());
            return Result.error(401, "未认证，请提供有效的JWT Token或API Key");
        } catch (InsufficientPointsException e) {
            log.warn("用户积分不足，无法创建任务: {}", e.getMessage());
            return Result.error(402, "积分不足：" + e.getMessage());
        } catch (IllegalArgumentException e) {
            log.warn("任务参数错误: {}", e.getMessage());
            return Result.error(400, "参数错误：" + e.getMessage());
        } catch (Exception e) {
            log.error("创建任务时发生未知错误", e);
            return Result.error(500, "系统错误，请稍后重试");
        }
    }

    /**
     * 计算预计等待时间
     */
    private int calculateEstimatedWaitTime(long queuePosition) {
        // 根据模型的平均处理时间计算
        // 图片模型约10秒，视频模型约4-8分钟
        final int AVG_PROCESSING_TIME_SECONDS = 30;
        return (int) queuePosition * AVG_PROCESSING_TIME_SECONDS;
    }

    /**
     * 获取单个任务的详情
     * 
     * @param taskNo 任务编号
     * @return 任务详细信息
     */
    @GetMapping("/{taskNo}")
    @Operation(
        summary = "获取单个任务详情", 
        description = "根据任务编号查询AI任务的详细信息，包括状态、进度、结果URL等。仅能查询自己的任务。\n\n" +
                      "**认证方式**：JWT Token 或 API Key"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "查询成功"),
            @ApiResponse(responseCode = "401", description = "未认证"),
            @ApiResponse(responseCode = "404", description = "任务不存在或无权访问")
    })
    public Result<AiTaskDto> getTaskDetails(
            @Parameter(description = "任务编号", required = true, example = "TASK20251019143022ABC123")
            @PathVariable String taskNo) {
        try {
            // 从Spring Security上下文获取当前用户ID（支持JWT和API Key）
            Long currentUserId = com.dora.util.SecurityUtil.getCurrentUserId();
            
            log.info("用户 {} 查询任务详情，taskNo: {}", currentUserId, taskNo);
            
            AiTask task = aiTaskService.getTaskByTaskNo(taskNo, currentUserId);
            if (task == null) {
                log.warn("任务不存在或无权访问，taskNo: {}, userId: {}", taskNo, currentUserId);
                return Result.error(404, "任务不存在或无权访问");
            }
            
            log.info("成功查询任务详情，taskNo: {}, status: {}", taskNo, task.getStatus());
            return Result.success(AiTaskDto.fromEntity(task));
        } catch (com.dora.exception.AuthenticationException e) {
            log.warn("用户未认证: {}", e.getMessage());
            return Result.error(401, "未认证，请提供有效的JWT Token或API Key");
        }
    }

    /**
     * 获取用户的任务列表
     * 
     * @param page 页码
     * @param size 每页数量
     * @param status 状态筛选（可选）
     * @return 分页的任务列表
     */
    @GetMapping("/list")
    @Operation(
        summary = "获取用户任务列表", 
        description = "分页查询当前用户的所有AI任务，支持按状态和任务类型筛选。" +
                      "任务按创建时间倒序排列，最新的任务在最前面。\n\n" +
                      "**认证方式**：JWT Token 或 API Key\n\n" +
                      "**任务类型**：\n" +
                      "- text_to_image: 文生图\n" +
                      "- text_to_video: 文生视频\n" +
                      "- image_to_video: 图生视频\n" +
                      "- image_to_image: 图生图\n" +
                      "- llm: 大语言模型\n" +
                      "- text_to_audio: 文生音频\n" +
                      "- image_to_text: 图生文\n" +
                      "- other: 其他"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "查询成功"),
            @ApiResponse(responseCode = "401", description = "未认证")
    })
    public Result<PageInfo<AiTaskDto>> getUserTasks(
            @Parameter(description = "页码", example = "1") 
            @RequestParam(defaultValue = "1") int page,
            
            @Parameter(description = "每页数量", example = "10") 
            @RequestParam(defaultValue = "10") int size,
            
            @Parameter(description = "按状态筛选 (created/queued/processing/completed/failed/cancelled)") 
            @RequestParam(required = false) String status,
            
            @Parameter(description = "按任务类型筛选 (text_to_image/text_to_video/image_to_video等)") 
            @RequestParam(required = false) String taskType) {
        
        try {
            // 从Spring Security上下文获取当前用户ID（支持JWT和API Key）
            Long currentUserId = com.dora.util.SecurityUtil.getCurrentUserId();

            log.info("用户 {} 查询任务列表，page={}, size={}, status={}, taskType={}", 
                    currentUserId, page, size, status, taskType);

            PageHelper.startPage(page, size);
            List<AiTaskWithPlazaDto> tasksWithPlaza;
            
            // 根据是否有taskType参数选择不同的查询方法
            if (taskType != null && !taskType.trim().isEmpty()) {
                tasksWithPlaza = aiTaskService.getUserTasksWithPlazaAndType(currentUserId, status, taskType);
            } else {
                tasksWithPlaza = aiTaskService.getUserTasksWithPlaza(currentUserId, status);
            }
            
            PageInfo<AiTaskWithPlazaDto> pageInfo = new PageInfo<>(tasksWithPlaza);

            // 将联合查询结果转换为DTO列表
            List<AiTaskDto> dtoList = tasksWithPlaza.stream()
                    .map(AiTaskWithPlazaDto::toAiTaskDto)
                    .collect(Collectors.toList());
            
            PageInfo<AiTaskDto> dtoPageInfo = new PageInfo<>(dtoList);
            dtoPageInfo.setTotal(pageInfo.getTotal());
            dtoPageInfo.setPages(pageInfo.getPages());
            
            log.info("成功查询任务列表，总数: {}, 当前页数量: {}", dtoPageInfo.getTotal(), dtoList.size());
            
            return Result.success(dtoPageInfo);
        } catch (com.dora.exception.AuthenticationException e) {
            log.warn("用户未认证: {}", e.getMessage());
            return Result.error(401, "未认证，请提供有效的JWT Token或API Key");
        }
    }

    /**
     * 通用删除接口 - 支持删除AI任务或广场作品
     * 
     * @param id 任务编号或广场作品编号
     * @return 删除结果
     */
    @DeleteMapping("/delete/{id}")
    @Operation(
        summary = "通用删除接口", 
        description = "根据ID删除AI任务或广场作品。系统会自动识别ID类型并执行相应的删除操作。\n\n" +
                      "**支持的ID类型**：\n" +
                      "- AI任务编号（格式：TASK-开头）\n" +
                      "- 广场作品编号（格式：WORK-开头）\n\n" +
                      "**删除规则**：\n" +
                      "- 只能删除属于自己的内容\n" +
                      "- 正在处理中的AI任务无法删除\n" +
                      "- 删除AI任务时会同时删除相关的广场作品\n" +
                      "- 删除广场作品不会影响对应的AI任务\n" +
                      "- 删除任务时不会退还积分\n\n" +
                      "**认证方式**：JWT Token 或 API Key"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "删除成功"),
            @ApiResponse(responseCode = "400", description = "删除失败 - 内容不存在、无权删除或任务正在处理中"),
            @ApiResponse(responseCode = "401", description = "未认证")
    })
    public Result<String> deleteByIdUniversal(
            @Parameter(description = "任务编号或广场作品编号", required = true, 
                      example = "TASK-20251030123456-1234 或 WORK-20251030123456-1234")
            @PathVariable String id) {
        try {
            // 从Spring Security上下文获取当前用户ID
            Long currentUserId = com.dora.util.SecurityUtil.getCurrentUserId();
            
            log.info("用户 {} 请求删除内容，ID: {}", currentUserId, id);
            
            // 根据ID格式判断是AI任务还是广场作品
            if (id.startsWith("TASK-") || id.startsWith("TASK")) {
                // 删除AI任务
                boolean success = aiTaskService.deleteUserTask(id, currentUserId);
                if (success) {
                    log.info("AI任务删除成功，taskNo: {}, userId: {}", id, currentUserId);
                    return Result.success("AI任务删除成功", "任务 " + id + " 及相关广场作品已删除");
                } else {
                    log.warn("AI任务删除失败，taskNo: {}, userId: {}", id, currentUserId);
                    return Result.error(400, "删除失败：AI任务不存在、无权删除或任务正在处理中");
                }
            } else if (id.startsWith("WORK-") || id.startsWith("WORK")) {
                // 删除广场作品
                try {
                    plazaService.deleteWork(currentUserId, id);
                    log.info("广场作品删除成功，workNo: {}, userId: {}", id, currentUserId);
                    return Result.success("广场作品删除成功", "作品 " + id + " 已删除");
                } catch (IllegalArgumentException e) {
                    log.warn("广场作品删除失败，workNo: {}, userId: {}, error: {}", id, currentUserId, e.getMessage());
                    return Result.error(400, "删除失败：" + e.getMessage());
                }
            } else {
                log.warn("无法识别的ID格式，ID: {}", id);
                return Result.error(400, "无法识别的ID格式，请提供有效的任务编号或广场作品编号");
            }
        } catch (com.dora.exception.AuthenticationException e) {
            log.warn("用户未认证: {}", e.getMessage());
            return Result.error(401, "未认证，请提供有效的JWT Token或API Key");
        } catch (Exception e) {
            log.error("删除内容时发生异常，ID: {}", id, e);
            return Result.error(500, "系统错误，请稍后重试");
        }
    }

    /**
     * 删除AI任务及相关广场作品
     * 
     * @param taskNo 任务编号
     * @return 删除结果
     */
    @DeleteMapping("/{taskNo}")
    @Operation(
        summary = "删除AI任务", 
        description = "删除指定的AI任务及其相关的广场作品。只能删除自己的任务，且正在处理中的任务无法删除。\n\n" +
                      "**删除规则**：\n" +
                      "- 只能删除属于自己的任务\n" +
                      "- 正在处理中(processing)的任务无法删除\n" +
                      "- 删除任务时会同时删除相关的广场作品\n" +
                      "- 删除任务时不会退还积分\n\n" +
                      "**认证方式**：JWT Token 或 API Key"
    )
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "删除成功"),
            @ApiResponse(responseCode = "400", description = "删除失败 - 任务不存在、无权删除或任务正在处理中"),
            @ApiResponse(responseCode = "401", description = "未认证")
    })
    public Result<String> deleteTask(
            @Parameter(description = "任务编号", required = true, example = "TASK20251019143022ABC123")
            @PathVariable String taskNo) {
        try {
            // 从Spring Security上下文获取当前用户ID
            Long currentUserId = com.dora.util.SecurityUtil.getCurrentUserId();
            
            log.info("用户 {} 请求删除AI任务，taskNo: {}", currentUserId, taskNo);
            
            boolean success = aiTaskService.deleteUserTask(taskNo, currentUserId);
            if (success) {
                log.info("AI任务删除成功，taskNo: {}, userId: {}", taskNo, currentUserId);
                return Result.success("任务删除成功", "任务 " + taskNo + " 及相关广场作品已删除");
            } else {
                log.warn("AI任务删除失败，taskNo: {}, userId: {}", taskNo, currentUserId);
                return Result.error(400, "删除失败：任务不存在、无权删除或任务正在处理中");
            }
        } catch (com.dora.exception.AuthenticationException e) {
            log.warn("用户未认证: {}", e.getMessage());
            return Result.error(401, "未认证，请提供有效的JWT Token或API Key");
        } catch (Exception e) {
            log.error("删除AI任务时发生异常，taskNo: {}", taskNo, e);
            return Result.error(500, "系统错误，请稍后重试");
        }
    }
}
