package com.njcn.device.pq.controller;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.njcn.common.config.GeneralInfo;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import com.njcn.device.pq.mapper.ResourceMapper;
import com.njcn.device.pq.pojo.po.ResourceData;
import com.njcn.device.pq.service.ResourceService;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.web.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

/**
 * @version 1.0.0
 * @author: zbj
 * @date: 2023/05/25
 */
@Slf4j
@Api(tags = "资源管理")
@RestController
@RequestMapping("/resource")
@RequiredArgsConstructor
public class ResourceController extends BaseController {

    private final ResourceService iResourceAdministrationService;

    private final ResourceMapper resourceMapper;

    private final FileStorageUtil fileStorageUtil;

    private final GeneralInfo generalInfo;

    /**
     * 上传资源
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/uploadFile")
    @ApiOperation("上传资源")
    public HttpResult<Boolean> uploadFile(@ApiParam(value = "文件", required = true) MultipartFile multipartFile,
                                          @ApiParam(value = "文件", required = false)  MultipartFile picture,
                                          @ApiParam(value = "资源名称", required = true) String name,
                                          @ApiParam(value = "资源状态", required = true) Integer state,
                                          @ApiParam(value = "资源类型", required = true) Integer type) {
        String methodDescribe = getMethodDescribe("uploadFile");
        Boolean flag = iResourceAdministrationService.uploadFile(multipartFile, picture, name, state, type);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, flag, methodDescribe);
    }

    /**
     * 查询数据
     *
     * @return List<ResourceData>
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/queryData")
    @ApiOperation("查询数据")
    public HttpResult<List<ResourceData>> queryData(@ApiParam(value = "资源类型", required = false) Integer type,
                                                    @ApiParam(value = "资源状态", required = false) Integer state,
                                                    @ApiParam(value = "搜索框数据", required = false) String searchValue) {
        String methodDescribe = getMethodDescribe("queryData");
        List<ResourceData> result = iResourceAdministrationService.queryData(type, state, searchValue);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
    }


    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/play1")
    @ApiOperation("播放视频资源")
    @ApiImplicitParam(name = "id", value = "id", required = true)
    public void play1(@RequestParam("id") String id, HttpServletRequest request, HttpServletResponse response) {
        ResourceData resourceData = resourceMapper.selectById(id);
        fileStorageUtil.downloadStream(response, resourceData.getResUrl());
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/play2")
    @ApiOperation("播放视频资源")
    @ApiImplicitParam(name = "id", value = "id", required = true)
    public void play2(@RequestParam("id") String id, HttpServletRequest request, HttpServletResponse response) {
        RandomAccessFile targetFile = null;
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            response.reset();
            //获取请求头中Range的值
            String rangeString = request.getHeader(HttpHeaders.RANGE);
            //打开文件
            File file = File.createTempFile(IdWorker.getIdStr(), ".mp4");
            ResourceData resourceData = resourceMapper.selectById(id);
            InputStream ins = fileStorageUtil.getFileStream(resourceData.getResUrl());
            long l = System.currentTimeMillis();
            FileUtil.writeFromStream(ins, file);
            long ll = System.currentTimeMillis();
            System.out.println("流转文件耗时：" + (ll - l) + "=============================");
            if (file.exists()) {
                //使用RandomAccessFile读取文件
                targetFile = new RandomAccessFile(file, "r");
                long fileLength = targetFile.length();
                long requestSize = (int) fileLength;
                //分段下载视频
                if (StringUtils.hasText(rangeString)) {
                    //从Range中提取需要获取数据的开始和结束位置
                    long requestStart = 0, requestEnd = 0;
                    String[] ranges = rangeString.split("=");
                    if (ranges.length > 1) {
                        String[] rangeDatas = ranges[1].split("-");
                        requestStart = Integer.parseInt(rangeDatas[0]);
                        if (rangeDatas.length > 1) {
                            requestEnd = Integer.parseInt(rangeDatas[1]);
                        }
                    }
                    if (requestEnd != 0 && requestEnd > requestStart) {
                        requestSize = requestEnd - requestStart + 1;
                    }
                    //根据协议设置请求头
                    response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
                    response.setHeader(HttpHeaders.CONTENT_TYPE, "video/mp4");
                    if (!StringUtils.hasText(rangeString)) {
                        response.setHeader(HttpHeaders.CONTENT_LENGTH, fileLength + "");
                    } else {
                        long length;
                        if (requestEnd > 0) {
                            length = requestEnd - requestStart + 1;
                            response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + requestEnd + "/" + fileLength);
                        } else {
                            length = fileLength - requestStart;
                            response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + (fileLength - 1) + "/"
                                    + fileLength);
                        }
                    }
                    //断点传输下载视频返回206
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设置targetFile，从自定义位置开始读取数据
                    targetFile.seek(requestStart);
                } else {
                    //如果Range为空则下载整个视频
                    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=demo.mp4");
                    //设置文件长度
                    response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));
                }

                //从磁盘读取数据流返回
                byte[] cache = new byte[4096];
                try {
                    while (requestSize > 0) {
                        int len = targetFile.read(cache);
                        if (requestSize < cache.length) {
                            outputStream.write(cache, 0, (int) requestSize);
                        } else {
                            outputStream.write(cache, 0, len);
                            if (len < cache.length) {
                                break;
                            }
                        }
                        requestSize -= cache.length;
                    }
                } catch (IOException e) {
                    // tomcat原话。写操作IO异常几乎总是由于客户端主动关闭连接导致，所以直接吃掉异常打日志
                    //比如使用video播放视频时经常会发送Range为0- 的范围只是为了获取视频大小，之后就中断连接了
                    log.info(e.getMessage());
                }
            } else {
                throw new RuntimeException("文件路径有误");
            }
            outputStream.flush();
        } catch (Exception e) {
            log.error("文件传输错误", e);
            throw new RuntimeException("文件传输错误");
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("流释放错误", e);
                }
            }
            if (targetFile != null) {
                try {
                    targetFile.close();
                } catch (IOException e) {
                    log.error("文件流释放错误", e);
                }
            }
        }
    }

    /**
     * 修改资源
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/updateFile")
    @ApiOperation("修改资源")
    public HttpResult<Boolean> updateFile(@ApiParam(value = "id", required = true) String id,
                                          @ApiParam(value = "文件", required = false) MultipartFile multipartFile,
                                          @ApiParam(value = "图片", required = false) MultipartFile picture,
                                          @ApiParam(value = "资源名称", required = false) String name,
                                          @ApiParam(value = "资源状态", required = false) Integer state,
                                          @ApiParam(value = "资源类型", required = false) Integer type) {
        String methodDescribe = getMethodDescribe("updateFile");
        Boolean flag = iResourceAdministrationService.updateFile(id, multipartFile, picture, name, state, type);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, flag, methodDescribe);
    }

    /**
     * 删除资源
     */
    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @GetMapping("/deleteFile")
    @ApiOperation("删除资源")
    @ApiImplicitParam(name = "id", value = "id", required = true)
    public HttpResult<Boolean> deleteFile(@RequestParam("id") String id) {
        String methodDescribe = getMethodDescribe("deleteFile");
        Boolean flag = iResourceAdministrationService.deleteFile(id);
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, flag, methodDescribe);
    }

/*

 /**
     * 导出数据
     *//*
     *//*@OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @PostMapping("/exportData")
    @ApiOperation("导出数据")
    public HttpResult<Object> exportData() {
        String methodDescribe = getMethodDescribe("exportData");
        iResourceAdministrationService.exportData();
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, "成功", methodDescribe);
    }*/
}
