package com.tofly.feesapi.file;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tofly.feesapi.common.core.ResultRespone;
import com.tofly.common.core.util.StringUtil;
import com.tofly.common.core.util.io.IOUtil;
import com.tofly.feesapi.common.BaseController;
import com.tofly.feesapi.common.exception.FeesException;
import com.tofly.feesapi.config.FilePathBean;
import com.tofly.feesapi.file.entity.File;
import com.tofly.feesapi.file.entity.dto.FileDto;
import com.tofly.feesapi.file.entity.vo.FileVo;
import com.tofly.feesapi.file.fileconfiguration.FileStorageService;
import com.tofly.feesapi.file.service.IFileInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/file")
@Api(tags = "附件信息表接口")
public class FileController extends BaseController {

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private IFileInfoService iFileInfoService;
    @Autowired
    private FilePathBean filePathBean;

    /**
     * 分页查询
     */
    @GetMapping("/page")
    @ApiOperation(value = "分页查询")
    public ResultRespone<Page<File>> getDpViewsPage(Page page, FileDto parDto) {
        ResultRespone<Page<File>> rest = new ResultRespone<>();
        try {
            Page<File> filePage = iFileInfoService.page(page,
                    new QueryWrapper<File>().lambda()
                            .eq(StringUtil.isNotEmpty(parDto.getTableid()), File::getTableBh, parDto.getTableid())
                            .eq(StringUtil.isNotEmpty(parDto.getTablename()), File::getTableName, parDto.getTablename())
                            .eq(StringUtil.isNotEmpty(parDto.getCbrq()), File::getFileNote, parDto.getCbrq())
                            .and(
                                    StringUtil.isNotEmpty(parDto.getSearchStr()), wrapper -> wrapper
                                            .like(StringUtil.isNotEmpty(parDto.getSearchStr()), File::getFileOldFn, parDto.getSearchStr())
                            )
            );
            rest.setCode(1);
            rest.setResult(filePage);
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }


    /**
     * 通过id查询附件信息表
     */
    @GetMapping("/{id}")
    @ApiOperation(value = "通过ID查询")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "Long")
    })
    public ResultRespone getById(@PathVariable("id") Long id) {

        return ResultRespone.success(iFileInfoService.getById(id));
    }

    /**
     * 新增附件信息表
     */
    @ApiOperation(value = "新增附件信息表")
    @PostMapping(headers = "content-type=multipart/form-data")
    public ResultRespone save(HttpServletRequest servletRequest, FileVo file, BindingResult result) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        try {
            String path = filePathBean.getOtherfile();
            iFileInfoService.savafile(servletRequest, path, file.getTableId(), file.getTableName());
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }

    /**
     * 新增附件信息表
     */
    @ApiOperation(value = "新增附件信息表")
    @PostMapping(value = "/saveMultipartFile", headers = "content-type=multipart/form-data")
    public ResultRespone saveMultipartFile(
            @RequestParam(value = "fileList", required = false) List<MultipartFile> fileList,
            @Valid FileVo file, BindingResult result) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        try {
            String path = filePathBean.getOtherfile();
            iFileInfoService.saveFileList(fileList, path, file.getTableId(), file.getTableName());
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }

    @ApiOperation(value = "新增附件信息表(返回附件信息)")
    @PostMapping(value = "/upfiles", headers = "content-type=multipart/form-data")
    public ResultRespone newsave(HttpServletRequest servletRequest) {
        ResultRespone<Object> rest = new ResultRespone<>();
        try {
            rest.setCode(1);
            rest.setResult(iFileInfoService.savafile(servletRequest, filePathBean.getOtherfile()));
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }

    /**
     * 通过id删除附件信息表
     */
    @ApiOperation(value = "通过ID删除附件信息表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "Long")
    })
    @DeleteMapping("/{id}")
    public ResultRespone removeById(@PathVariable String id) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        try {
            List<String> listid = new ArrayList<>();
            listid.add(id);
            iFileInfoService.removeFileListById(listid);
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }

    /**
     * 通过id批量删除附件信息表
     */
    @ApiOperation(value = "通过ID批量删除附件信息表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ids", value = "批量删除，多个id以逗号隔开", required = true, dataType = "String")
    })
    @DeleteMapping("/deleteByIds")
    public ResultRespone removeByIds(String ids) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        try {
            List<String> removeId = Arrays.stream(ids.split(",")).collect(Collectors.toList());
            iFileInfoService.removeFileListById(removeId);
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }


    /**
     * 通过id下载附件
     */
    @ApiOperation(value = "通过id下载附件")
    @GetMapping("/download")
    public ResultRespone download(String id, HttpServletRequest request, HttpServletResponse response) {
        ResultRespone<Object> rest = new ResultRespone<>();
        rest.setCode(1);
        try {
            File file = iFileInfoService.getById(id);
            rest.setResult(fileStorageService.download(file.getFileNewFn(), request, response));
        } catch (FeesException e) {
            rest.setCode(e.getErrorCode().getErrorCode());
            rest.setMessage(e.getMessage());
        }
        return rest;
    }

    /**
     * 返回图片
     */
    @GetMapping(value = "/loadImg")
    @ApiOperation(value = "根据FTP文件地址获取图片")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "remotePath", value = "图片地址", required = true, dataType = "String"),
            @ApiImplicitParam(name = "access_token", value = "token信息", required = true, dataType = "String"),
            @ApiImplicitParam(name = "showSmallPic", value = "是否压缩图片,1是", required = false, dataType = "String"),
            @ApiImplicitParam(name = "compressionRation", value = "压缩图片比例0到1之间，如0.5", required = false, dataType = "String")
    })
    public byte[] loadFileImg(@RequestParam(value = "remotePath") String remotePath,
                              @RequestParam(value = "access_token") String access_token,
                              String showSmallPic, String compressionRation, HttpServletResponse response) {
        String fileType = remotePath.substring(remotePath.lastIndexOf("."));
        if (StringUtil.isNotEmpty(fileType)) {
            fileType = fileType.toLowerCase();
        } else {
            return null;
        }
        byte[] b;
        if (StringUtil.isNotBlank(showSmallPic) && showSmallPic.equals("1")) {
            double ration = Double.parseDouble(StringUtil.isNotBlank(compressionRation) ? compressionRation : "0.5");
            b = loadFileSmallImg(remotePath, ration);
        } else {
            b = fileStorageService.getByteDataforFile(remotePath);
        }

        if (b == null) {
            return null;
        }
        switch (fileType) {
            case ".jpg":
            case ".jpeg":
                response.setContentType(MediaType.IMAGE_JPEG_VALUE);
                break;
            case ".png":
                response.setContentType(MediaType.IMAGE_PNG_VALUE);
                break;
            case ".gif":
                response.setContentType(MediaType.IMAGE_GIF_VALUE);
                break;
            case ".pdf":
                response.setContentType(MediaType.APPLICATION_PDF_VALUE);
                break;
            default:
                response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
                break;
        }
        return b;
    }

    /**
     * 图片太大压缩图片大小
     */
    private byte[] loadFileSmallImg(String remotePath, double compressionRation) {
        try {
            String fileType = remotePath.substring(remotePath.lastIndexOf("."));
            String fileTypNew = ""; //文件类型
            if (StringUtil.isNotEmpty(fileType)) {
                fileType = fileType.toLowerCase();
                fileTypNew = fileType.split("\\.")[1];
            }
            //获取图片
            InputStream inputStream = fileStorageService.getByteDataforFileInputStream(remotePath);
            //原始图片填充
            BufferedImage orignalImage = ImageIO.read(inputStream);
            //压缩图片，得到新的高度，宽度
            int newWidth = (int) (orignalImage.getWidth() * compressionRation);
            int newHeight = (int) (orignalImage.getHeight() * compressionRation);
            //得到新的图片
            Image scImage = orignalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
            //图片填充
            BufferedImage bufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            bufferedImage.getGraphics().drawImage(scImage, 0, 0, null);
            //图片流输入
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, fileTypNew, outputStream);
            byte[] buffer = outputStream.toByteArray();
            inputStream.close();
            outputStream.close();
            return buffer;

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 音频流
     */
    @SneakyThrows
    @GetMapping(value = "/loadAudio")
    @ApiOperation(value = "根据FTP文件地址获取音频")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "remotePath", value = "音频文件地址", required = true, dataType = "String"),
            @ApiImplicitParam(name = "fileName", value = "文件名称", required = true, dataType = "String")

    })
    //@AutoLog(value = EntityType.ASSET,actionType = ActionType.SEARCHED)
    public void wavStream(String remotePath, String fileName, HttpServletRequest request, HttpServletResponse response) {
        //String remotePath = "/xnkd/demo/pic/海阔天空.mp3";

        java.io.File music = null;

        music = java.io.File.createTempFile("tmp", remotePath.substring(remotePath.lastIndexOf(".")));
        OutputStream ops = new FileOutputStream(music);
        Boolean isSucccess = fileStorageService.retrieveFile(remotePath, ops);
        log.info("=====写入临时文件成功与否：====" + isSucccess);

        if (!music.exists()) {
            log.info("不存在 文件名为：" + remotePath + "的音频文件！");
        }

        String range = request.getHeader("Range");
        //开始下载位置
        long startByte = 0;
        //结束下载位置
        long endByte = music.length() - 1;
        //有range的话
        if (range != null && range.contains("bytes=") && range.contains("-")) {
            range = range.substring(range.lastIndexOf("=") + 1).trim();
            String ranges[] = range.split("-");
            try {
                //判断range的类型
                if (ranges.length == 1) {
                    //类型一：bytes=-2343
                    if (range.startsWith("-")) {
                        endByte = Long.parseLong(ranges[0]);
                    }
                    //类型二：bytes=2343-
                    else if (range.endsWith("-")) {
                        startByte = Long.parseLong(ranges[0]);
                    }
                }
                //类型三：bytes=22-2343
                else if (ranges.length == 2) {
                    startByte = Long.parseLong(ranges[0]);
                    endByte = Long.parseLong(ranges[1]);
                }
            } catch (NumberFormatException e) {
                startByte = 0;
                endByte = music.length() - 1;
            }
        }
        //要下载的长度
        long contentLength = endByte - startByte + 1;
        //文件名
        //String fileName = music.getName();
        //文件类型
        String contentType = request.getServletContext().getMimeType(music.getName());
        //各种响应头设置
        //参考资料：https://www.ibm.com/developerworks/cn/java/joy-down/index.html
        //坑爹地方一：看代码
        response.setHeader("Accept-Ranges", "bytes");
        //坑爹地方二：http状态码要为206
        response.setStatus(206);
        response.setContentType(contentType);
        response.setHeader("Content-Type", contentType);
        //这里文件名换你想要的，inline表示浏览器直接实用（我方便测试用的）
        //参考资料：http://hw1287789687.iteye.com/blog/2188500
        response.setHeader("Content-Disposition", "inline;filename=" + fileName);
        response.setHeader("Content-Length", String.valueOf(contentLength));
        //坑爹地方三：Content-Range，格式为
        // [要下载的开始位置]-[结束位置]/[文件总大小]
        response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + music.length());
        BufferedOutputStream outputStream = null;
        RandomAccessFile randomAccessFile = null;
        //已传送数据大小
        long transmitted = 0;
        try {
            randomAccessFile = new RandomAccessFile(music, "r");
            outputStream = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[2048];
            int len = 0;
            randomAccessFile.seek(startByte);
            //坑爹地方四：判断是否到了最后不足4096（buff的length）个byte这个逻辑（(transmitted + len) <= contentLength）要放前面！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
            //不然会会先读取randomAccessFile，造成后面读取位置出错，找了一天才发现问题所在
            while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) {
                outputStream.write(buff, 0, len);
                transmitted += len;
                //停一下，方便测试，用的时候删了就行了
            }
            //处理不足buff.length部分
            if (transmitted < contentLength) {
                len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted));
                outputStream.write(buff, 0, len);
                transmitted += len;
            }
            outputStream.flush();
            response.flushBuffer();
            randomAccessFile.close();
            log.info("下载完毕：" + startByte + "-" + endByte + "：" + transmitted);
        } finally {
            try {
                if (randomAccessFile != null) {
                    randomAccessFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 返回图片
     */
    @GetMapping(value = "/downloadFile")
    @ApiOperation(value = "根据FTP文件地址下载文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "remotePath", value = "文件地址", required = true, dataType = "String"),
            @ApiImplicitParam(name = "fileName", value = "文件名称", required = true, dataType = "String")
    })
    @SneakyThrows
    //@AutoLog(value = EntityType.ASSET,actionType = ActionType.SEARCHED)
    public void downloadFile(String remotePath, String fileName, HttpServletResponse response, HttpServletRequest request) {
        byte[] data = fileStorageService.getByteDataforFile(remotePath);
        response.reset();
        response.setCharacterEncoding("UTF-8");
        String userAgent = request.getHeader("User-Agent");
        String formFileName;
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            // 针对IE或者以IE为内核的浏览器：
            formFileName = URLEncoder.encode(fileName, "UTF-8");
        } else {
            // 非IE浏览器的处理：
            formFileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
        }
        response.setHeader("Content-Disposition", String.format("attachment; filename=%s", formFileName));
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.setHeader("content-type", "application/octet-stream");
        try {
            IOUtil.write(response.getOutputStream(), Boolean.TRUE, data);
        } catch (IOException e) {
            //log.error(e.getMessage());
            e.getMessage();
        }
    }
}
