package com.example.controller;


import com.example.common.Result;
import com.example.common.enums.ResultCodeEnum;
import com.example.entity.Chunk;
import com.example.entity.Video;
import com.example.mapper.VideoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;

/**
 * 功能：前端视频上传
 *
 * @author 熊浩毅
 * @time 2024-04-17 19:31
 * @Description
 */
@RestController
@RequestMapping("/video")
@Slf4j
public class uploadVideoController {
    // 文件上传存储路径
    private static final String filePath = System.getProperty("user.dir") + "/files/videos";

    @Value("${server.port:8080}")
    private String port;

    @Value("${ip:localhost}")
    private String ip;
    @Resource
    private VideoMapper videoMapper;
    /**
     * 分片上传
     * 处理文件上传POST请求
     * 将上传的文件存放到服务器内
     *
     * @param chunk    文件块
     * @param response 响应
     * @return 上传响应状态
     * * 每一个上传块都会包含如下分块信息：
     * * chunkNumber: 当前块的次序，第一个块是 1，注意不是从 0 开始的。
     * * totalChunks: 文件被分成块的总数。
     * * chunkSize: 分块大小，根据 totalSize 和这个值你就可以计算出总共的块数。注意最后一块的大小可能会比这个要大。
     * * currentChunkSize: 当前块的大小，实际大小。
     * * totalSize: 文件总大小。
     * * identifier: 这个就是每个文件的唯一标示。
     * * filename: 文件名。
     * * relativePath: 文件夹上传的时候文件的相对路径属性。
     * * 一个分块可以被上传多次，当然这肯定不是标准行为，但是在实际上传过程中是可能发生这种事情的，这种重传也是本库的特性之一。
     * *
     * * 根据响应码认为成功或失败的：
     * * 200 文件上传完成
     * * 201 文加快上传成功
     * * 500 第一块上传失败，取消整个文件上传
     * * 507 服务器出错自动重试该文件块上传
     */
    @PostMapping("/fileUpload")
    public Result uploadPost(@RequestBody Chunk chunk, HttpServletResponse response)
    {
        log.info(chunk.toString());
        // 设置
//        Path absolutePath = Paths.get("").toAbsolutePath().resolve(saveVideoFilePath.substring(2) + "/videos");
//        String absoluteDiskPath = absolutePath.toString();
        String SavePath = filePath;
        File file = new File(SavePath, chunk.getFilename());
        if (!file.getParentFile().exists())
        {
            //如果不存在，就创建一个这个路径的文件夹。
            file.getParentFile().mkdirs();
        }
        //第一个块,则新建文件
        if (chunk.getChunkNumber() == 1 && !file.exists())
        {
            try
            {
                file.createNewFile();
            }
            catch (IOException e)
            {
                response.setStatus(500);
                return Result.error(ResultCodeEnum.UPLOAD_ERROR);
            }
        }

        //进行写文件操作
        try (
                //将块文件写入文件中
                InputStream fos = chunk.getFile().getInputStream(); RandomAccessFile raf = new RandomAccessFile(file, "rw"))
        {
            int len = -1;
            byte[] buffer = new byte[1024];
            raf.seek((chunk.getChunkNumber() - 1) * chunk.getChunkSize());
            while ((len = fos.read(buffer)) != -1)
            {
                raf.write(buffer, 0, len);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
            if (chunk.getChunkNumber() == 1)
            {
                file.delete();
            }
            response.setStatus(507);
            return Result.error(ResultCodeEnum.WRITE_ERROR);
        }
        // 全部加载完成了数据块
        if (chunk.getChunkNumber().equals(chunk.getTotalChunks()))
        {
            response.setStatus(200);
            // TODO 向数据库中保存上传信息
            String videoNameText = chunk.getFilename();
            // 获取文件后缀，因此此后端代码可接收一切文件，上传格式前端限定
            String fileExt = videoNameText.substring(videoNameText.lastIndexOf(".") + 1).toLowerCase();
            // UUID(全局唯一标识符)randomUUID(随机生成标识符)toString(转成字符串)replaceAll(替换字符方法，因为随机生成的里面包括了 - ，这里意思是把 - 全部换成空)
            String pikId = UUID.randomUUID().toString().replaceAll("-", "");
            // 视频名字拼接：唯一标识符加上点，再加上上面的视频后缀也就是MP4之类的。就组成了现在的视频名字，比如这样：c7bbc1f9664947a287d35dd7cdc48a95.mp4
            String newVideoName = pikId + "." + fileExt;
            System.out.println("原文件名：" + videoNameText);
            System.out.println("重构文件名防止上传同名文件：" + newVideoName);
            // 把已保存的原文件名文件改成新文件名
            try
            {
                Files.move(Paths.get(SavePath + "/" + videoNameText), Paths.get(SavePath + "/" + newVideoName));
            }
            catch (IOException e)
            {
                return Result.error();
            }
            //保存视频url路径地址
            String videoUrl = SavePath + "/" + newVideoName;
            //调用数据库接口插入数据库方法save，把视频原名，视频路径，视频的唯一标识码传进去存到数据库内
            // TODO
            //videoUploadMapper.save(videoNameText, videoUrl, newVideoName);
            videoMapper.insert(new Video(newVideoName,videoUrl,newVideoName));
            return Result.success();
        }
        else
        {
            response.setStatus(201);
            return Result.success();
        }
    }
}
