package com.microservices.file.controller;

import com.microservices.common.core.web.controller.BaseController;
import com.microservices.common.core.web.domain.AjaxResult;
import com.microservices.common.core.web.domain.GenericsAjaxResult;
import com.microservices.file.domain.vo.CheckChunkVo;
import com.microservices.file.domain.vo.CheckInstantUploadVo;
import com.microservices.file.domain.vo.InitChunkedUploadVo;
import com.microservices.file.domain.vo.UploadProgressVo;
import com.microservices.file.domain.vo.input.CheckInstantUploadInputVo;
import com.microservices.file.domain.vo.input.InitChunkedUploadInputVo;
import com.microservices.file.domain.vo.response.*;
import com.microservices.file.service.IChunkedUploadService;
import com.microservices.system.api.domain.SysFileInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.Map;

/**
 * 分片上传控制器
 *
 * @author microservices
 */
@RestController
@RequestMapping("/chunked")
@Api(tags = "分片上传接口")
public class ChunkedUploadController extends BaseController {

    @Autowired
    private IChunkedUploadService chunkedUploadService;

    /**
     * 初始化分片上传
     * <p>
     * 功能：
     * 1. 创建上传会话
     * 2. 根据文件大小判断哈希类型（FULL/SAMPLE）
     * 3. 返回采样点信息（SAMPLE类型）
     *
     * @param input 初始化上传请求参数
     * @return 初始化结果，包含 uploadId、totalChunks、chunkSize、hashType、sampleChunks
     */
    @PostMapping("/init")
    @ApiOperation("初始化分片上传")
    public GenericsAjaxResult<InitChunkedUploadResponseVo> initChunkedUpload(@Validated @RequestBody InitChunkedUploadInputVo input) {
        InitChunkedUploadVo result = chunkedUploadService.initChunkedUpload(input);
        return genericsSuccess(InitChunkedUploadResponseVo.from(result));
    }

    /**
     * 检查秒传（简化版）
     * <p>
     * 功能：
     * 1. 校验上传会话和时间窗口
     * 2. 查询是否存在相同的 file_hash 且状态为已完成
     * 3. 秒传成功：删除当前会话，返回已存在文件信息
     * 4. 不能秒传：返回继续上传
     *
     * @param input 检查秒传请求参数
     * @return 检查结果
     */
    @PostMapping("/checkInstantUpload")
    @ApiOperation("检查秒传")
    public GenericsAjaxResult<CheckInstantUploadResponseVo> checkInstantUpload(@Validated @RequestBody CheckInstantUploadInputVo input) {
        CheckInstantUploadVo result = chunkedUploadService.checkInstantUpload(input.getUploadId(), input.getFileSignature());
        return genericsSuccess(CheckInstantUploadResponseVo.from(result));
    }

    /**
     * 检查分片是否已上传（断点续传）
     *
     * @param uploadId    上传ID
     * @param chunkNumber 分片序号
     * @return 分片检查结果
     */
    @GetMapping("/check/{uploadId}/{chunkNumber}")
    @ApiOperation("检查分片是否已上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uploadId", value = "上传ID", paramType = "path", dataType = "String", required = true),
            @ApiImplicitParam(name = "chunkNumber", value = "分片序号", paramType = "path", dataType = "Integer", required = true)
    })
    public GenericsAjaxResult<CheckChunkResponseVo> checkChunk(@PathVariable("uploadId") String uploadId, @PathVariable("chunkNumber") Integer chunkNumber) {
        CheckChunkVo result = chunkedUploadService.checkChunk(uploadId, chunkNumber);
        return genericsSuccess(CheckChunkResponseVo.from(result));
    }

    /**
     * 上传分片
     *
     * @param uploadId    上传ID
     * @param chunkNumber 分片序号
     * @param chunk       分片文件
     * @return 上传结果
     */
    @PostMapping("/upload/{uploadId}/{chunkNumber}")
    @ApiOperation("上传分片")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uploadId", value = "上传ID", paramType = "path", dataType = "String", required = true),
            @ApiImplicitParam(name = "chunkNumber", value = "分片序号", paramType = "path", dataType = "Integer", required = true),
            @ApiImplicitParam(name = "chunk", value = "分片文件", paramType = "form", dataType = "_file", required = true)
    })
    public GenericsAjaxResult<UploadChunkResponseVo> uploadChunk(
            @PathVariable("uploadId") String uploadId,
            @PathVariable("chunkNumber") Integer chunkNumber,
            @RequestPart("chunk") MultipartFile chunk) {
        chunkedUploadService.uploadChunk(uploadId, chunkNumber, chunk);
        return genericsSuccess(UploadChunkResponseVo.success(chunkNumber));
    }

    /**
     * 合并分片（异步）
     * <p>
     * 功能：
     * 1. 提交合并任务，立即返回
     * 2. 客户端通过轮询进度接口获取合并结果
     *
     * @param uploadId 上传ID
     * @return 合并任务提交结果
     */
    @PostMapping("/merge/{uploadId}")
    @ApiOperation("合并分片")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uploadId", value = "上传ID", paramType = "path", dataType = "String", required = true)
    })
    public GenericsAjaxResult<Map<String, String>> mergeChunks(@PathVariable("uploadId") String uploadId) {
        chunkedUploadService.mergeChunks(uploadId);
        Map<String, String> result = new HashMap<>();
        result.put("uploadId", uploadId);
        result.put("message", "合并任务已提交，请通过进度接口查询结果");
        return genericsSuccess(result);
    }

    /**
     * 取消上传
     * <p>
     * 功能：
     * 1. 删除上传会话记录
     * 2. 清理已上传的分片文件
     *
     * @param uploadId 上传ID
     * @return 取消结果
     */
    @DeleteMapping("/cancel/{uploadId}")
    @ApiOperation("取消上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uploadId", value = "上传ID", paramType = "path", dataType = "String", required = true)
    })
    public GenericsAjaxResult<CancelUploadResponseVo> cancelUpload(@PathVariable("uploadId") String uploadId) {
        boolean result = chunkedUploadService.cancelUpload(uploadId);
        return genericsSuccess(result ? CancelUploadResponseVo.success() : CancelUploadResponseVo.failed("取消上传失败"));
    }

    /**
     * 获取上传进度
     *
     * @param uploadId 上传ID
     * @return 上传进度
     */
    @GetMapping("/progress/{uploadId}")
    @ApiOperation("获取上传进度")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uploadId", value = "上传ID", paramType = "path", dataType = "String", required = true)
    })
    public GenericsAjaxResult<UploadProgressResponseVo> getProgress(@PathVariable("uploadId") String uploadId) {
        UploadProgressVo progress = chunkedUploadService.getProgress(uploadId);
        return genericsSuccess(UploadProgressResponseVo.from(progress));
    }
}
