package vip.xiaonuo.disk.controller;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.qiwenshare.common.anno.MyLog;
import com.qiwenshare.common.result.RestResult;
import com.qiwenshare.common.util.MimeUtils;
import com.qiwenshare.ufop.factory.UFOPFactory;
import com.qiwenshare.ufop.operation.download.Downloader;
import com.qiwenshare.ufop.operation.download.domain.DownloadFile;
import com.qiwenshare.ufop.operation.download.domain.Range;
import com.qiwenshare.ufop.util.UFOPUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.disk.domain.FileBean;
import vip.xiaonuo.disk.domain.ResourceFile;
import vip.xiaonuo.disk.domain.ResourceUserFile;
import vip.xiaonuo.disk.domain.UserFile;
import vip.xiaonuo.disk.dto.file.*;
import vip.xiaonuo.disk.io.QiwenFile;
import vip.xiaonuo.disk.domain.StorageBean;
import vip.xiaonuo.disk.dto.file.UploadFileDTO;
import vip.xiaonuo.disk.service.IStorageReService;
import vip.xiaonuo.disk.service.ResourceFileService;
import vip.xiaonuo.disk.service.ResourceUserfileService;
import vip.xiaonuo.disk.vo.file.UploadFileVo;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Slf4j
@Tag(name = "filetransfer", description = "该接口为文件传输接口，主要用来做文件的上传、下载和预览，用于在线教育单拆")
@RestController
@RequestMapping("/resourceFile")
public class ResourceFileController {

    @Resource
    private ResourceFileService resourceFileService;

    @Resource
    private ResourceUserfileService resourceUserFileService;

    public static Executor executor = Executors.newFixedThreadPool(20);

    @Resource
    UFOPFactory ufopFactory;



    @Resource
    private IStorageReService storageReService;

    public static final String SUCCESS = "操作成功";

    public static final String CURRENT_MODULE = "文件传输接口";

    /**
     * 上传前校验状况接口
     * 校验是否已上传过无需上传
     * 校验是否已有分片，并将上传好的分片返给前端
     * */
    @Operation(summary = "极速上传", description = "校验文件MD5判断文件是否存在，如果存在直接上传成功并返回skipUpload=true，如果不存在返回skipUpload=false需要再次调用该接口的POST方法", tags = {"filetransfer"})
    @RequestMapping(value = "/uploadfile", method = RequestMethod.GET)
    @MyLog(operation = "极速上传", module = CURRENT_MODULE)
    @ResponseBody
    public RestResult<UploadFileVo> uploadFileSpeed(HttpServletRequest request, UploadFileDTO uploadFileDto) {
        String userId = StpLoginUserUtil.getLoginUser().getId();

        boolean isCheckSuccess = storageReService.checkStorage(userId, uploadFileDto.getTotalSize());
        if (!isCheckSuccess) {
            return RestResult.fail().message("存储空间不足");
        }
        UploadFileVo uploadFileVo = resourceFileService.uploadFileSpeed(request,userId,uploadFileDto);
        return RestResult.success().data(uploadFileVo);

    }


    @Operation(summary = "上传文件", description = "真正的上传文件接口", tags = {"filetransfer"})
    @RequestMapping(value = "/uploadfile", method = RequestMethod.POST)
    @MyLog(operation = "上传文件", module = CURRENT_MODULE)
    @ResponseBody
    public RestResult<UploadFileVo> uploadFile(HttpServletRequest request, UploadFileDTO uploadFileDto) {
        String userId = StpLoginUserUtil.getLoginUser().getId();

        boolean isCheckSuccess = storageReService.checkStorage(userId, uploadFileDto.getTotalSize());
        if (!isCheckSuccess) {
            return RestResult.fail().message("存储空间不足");
        }
        resourceFileService.uploadFile(request, uploadFileDto, userId);

        UploadFileVo uploadFileVo =resourceFileService.uploadFile(request, uploadFileDto, userId);


        return RestResult.success().data(uploadFileVo);

    }

    @Operation(summary = "下载文件", description = "下载文件接口", tags = {"filetransfer"})
    @MyLog(operation = "下载文件", module = CURRENT_MODULE)
    @RequestMapping(value = "/downloadfile", method = RequestMethod.GET)
    public void downloadFile(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, DownloadFileDTO downloadFileDTO) {
//        Cookie[] cookieArr = httpServletRequest.getCookies();
        httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开
        ResourceUserFile resourceUserFile = resourceUserFileService.queryEntity(downloadFileDTO.getUserFileId());
        String fileName = "";
        if (resourceUserFile.getIsDir() == 1) {
            fileName = resourceUserFile.getFileName() + ".zip";
        } else {
            fileName = resourceUserFile.getFileName() + "." + resourceUserFile.getExtendName();

        }
        try {
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        httpServletResponse.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名

        resourceFileService.downloadFile(httpServletResponse, downloadFileDTO);

    }


    @Operation(summary = "批量下载文件", description = "批量下载文件", tags = {"filetransfer"})
    @RequestMapping(value = "/batchDownloadFile", method = RequestMethod.GET)
    @MyLog(operation = "批量下载文件", module = CURRENT_MODULE)
    @ResponseBody
    public void batchDownloadFile(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BatchDownloadFileDTO batchDownloadFileDTO) {

        String files = batchDownloadFileDTO.getUserFileIds();
        String[] userFileIdStrs = files.split(",");
        List<String> userFileIds = new ArrayList<>();
        for(String userFileId : userFileIdStrs) {
            ResourceUserFile resourceUserFile = resourceUserFileService.getById(userFileId);
            if (resourceUserFile.getIsDir() == 0) {
                userFileIds.add(userFileId);
            } else {
                QiwenFile qiwenFile = new QiwenFile(resourceUserFile.getFilePath(), resourceUserFile.getFileName(), true);
                List<ResourceUserFile> userFileList = resourceUserFileService.selectUserFileByLikeRightFilePath(qiwenFile.getPath(), resourceUserFile.getUserId());
                List<String> userFileIds1 = userFileList.stream().map(ResourceUserFile::getUserFileId).collect(Collectors.toList());
                userFileIds.add(resourceUserFile.getUserFileId());
                userFileIds.addAll(userFileIds1);
            }

        }
        ResourceUserFile userFile = resourceUserFileService.getById(userFileIdStrs[0]);
        httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开
        Date date = new Date();
        String fileName = String.valueOf(date.getTime());
        httpServletResponse.addHeader("Content-Disposition", "attachment;fileName=" + fileName + ".zip");// 设置文件名
    }

    @Operation(summary="预览文件", description="用于文件预览", tags = {"filetransfer"})
    @GetMapping("/preview")
    public void preview(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,  PreviewDTO previewDTO) throws IOException {

        if (previewDTO.getPlatform() != null && previewDTO.getPlatform() == 2) {
            resourceFileService.previewPictureFile(httpServletResponse, previewDTO);
            return ;
        }

        ResourceUserFile resourceUserFile = resourceUserFileService.getById(previewDTO.getUserFileId());


        String fileName = resourceUserFile.getFileName() + "." + resourceUserFile.getExtendName();
        try {
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        httpServletResponse.addHeader("Content-Disposition", "fileName=" + fileName);// 设置文件名
        String mime = MimeUtils.getMime(resourceUserFile.getExtendName());
        httpServletResponse.setHeader("Content-Type", mime);
        if (UFOPUtils.isImageFile(resourceUserFile.getExtendName())) {
            httpServletResponse.setHeader("cache-control", "public");
        }

        ResourceFile resourceFile = resourceFileService.getById(resourceUserFile.getFileId());
        if (UFOPUtils.isVideoFile(resourceUserFile.getExtendName()) || "mp3".equalsIgnoreCase(resourceUserFile.getExtendName()) || "flac".equalsIgnoreCase(resourceUserFile.getExtendName())) {
            //获取从那个字节开始读取文件
            String rangeString = httpServletRequest.getHeader("Range");
            int start = 0;
            if (StringUtils.isNotBlank(rangeString)) {
                start = Integer.parseInt(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
            }

            Downloader downloader = ufopFactory.getDownloader(resourceFile.getStorageType());
            DownloadFile downloadFile = new DownloadFile();
            downloadFile.setFileUrl(resourceFile.getFileUrl());
            Range range = new Range();
            range.setStart(start);

            if (start + 1024 * 1024 * 1 >= resourceFile.getFileSize().intValue()) {
                range.setLength(resourceFile.getFileSize().intValue() - start);
            } else {
                range.setLength(1024 * 1024 * 1);
            }
            downloadFile.setRange(range);
            InputStream inputStream = downloader.getInputStream(downloadFile);

            OutputStream outputStream = httpServletResponse.getOutputStream();
            try {

                //返回码需要为206，代表只处理了部分请求，响应了部分数据

                httpServletResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                // 每次请求只返回1MB的视频流

                httpServletResponse.setHeader("Accept-Ranges", "bytes");
                //设置此次相应返回的数据范围
                httpServletResponse.setHeader("Content-Range", "bytes " + start + "-" + (resourceFile.getFileSize() - 1) + "/" + resourceFile.getFileSize());
                IOUtils.copy(inputStream, outputStream);


            } finally {
                IOUtils.closeQuietly(inputStream);
                IOUtils.closeQuietly(outputStream);
                if (downloadFile.getOssClient() != null) {
                    downloadFile.getOssClient().shutdown();
                }
            }


        } else {
            resourceFileService.previewFile(httpServletResponse, previewDTO);

        }

    }

    @Operation(summary = "批量删除文件", description = "批量删除文件", tags = {"file"})
    @RequestMapping(value = "/batchdeletefile", method = RequestMethod.POST)
    @MyLog(operation = "批量删除文件", module = CURRENT_MODULE)
    @ResponseBody
    public RestResult<String> deleteImageByIds(HttpServletRequest httpServletRequest,@RequestBody BatchDeleteFileDTO batchDeleteFileDto) {
        String userFileIds = batchDeleteFileDto.getUserFileIds();
        String[] userFileIdList = userFileIds.split(",");
        resourceUserFileService.update(new UpdateWrapper<ResourceUserFile>().lambda().set(ResourceUserFile::getDeleteFlag, 1).in(ResourceUserFile::getUserFileId, Arrays.asList(userFileIdList)));
        for (String userFileId : userFileIdList) {
            executor.execute(()->{
                resourceUserFileService.deleteResourceUserFile(userFileId, StpLoginUserUtil.getLoginUser().getId());
            });
            ResourceUserFile resourceUserFile = resourceUserFileService.getById(userFileId);


        }

        return RestResult.success().message("批量删除文件成功");
    }

    @Operation(summary = "删除文件", description = "可以删除文件或者目录", tags = {"file"})
    @RequestMapping(value = "/deletefile", method = RequestMethod.POST)
    @MyLog(operation = "删除文件", module = CURRENT_MODULE)
    @ResponseBody
    public RestResult deleteFile(HttpServletRequest httpServletRequest,@RequestBody DeleteFileDTO deleteFileDto) {

//        JwtUser sessionUserBean =  SessionUtil.getSession();
        String userId = StpLoginUserUtil.getLoginUser().getId();
        resourceUserFileService.deleteResourceUserFile(deleteFileDto.getUserFileId(), userId);
        ResourceUserFile resourceUserFile = resourceUserFileService.getById(deleteFileDto.getUserFileId());

        return RestResult.success();

    }

    @Operation(summary = "资源库与素材库拉取文件", description = "真正的上传文件接口", tags = {"filetransfer"})
    @RequestMapping(value = "/eachOtherExchange", method = RequestMethod.POST)
    @MyLog(operation = "资源库与素材库拉取文件", module = CURRENT_MODULE)
    @ResponseBody
    public RestResult<UploadFileVo> eachOtherExchange(HttpServletRequest request, EachOtherExchangeDTO uploadFileDto) {
        String userId = StpLoginUserUtil.getLoginUser().getId();

        UploadFileVo uploadFileVo =resourceFileService.eachOtherExchange(request, uploadFileDto, userId);

        return RestResult.success().data(uploadFileVo);

    }


    @Operation(summary = "获取存储信息", description = "获取存储信息", tags = {"filetransfer"})
    @RequestMapping(value = "/getstorage", method = RequestMethod.GET)
    @ResponseBody
    public RestResult<StorageBean> getStorage(HttpServletRequest httpServletRequest) {

//        JwtUser sessionUserBean = SessionUtil.getSession();
        String userId = StpLoginUserUtil.getLoginUser().getId();
        StorageBean storageBean = new StorageBean();

        storageBean.setUserId(userId);


        Long storageSize = resourceFileService.selectStorageSizeByUserId(userId);
        StorageBean storage = new StorageBean();
        storage.setUserId(userId);
        storage.setStorageSize(storageSize);
        Long totalStorageSize = storageReService.getTotalStorageSize(userId);
        storage.setTotalStorageSize(totalStorageSize);
        return RestResult.success().data(storage);

    }

}
