package cc.smtweb.system.bpm.spring.controller;

import cc.smtweb.framework.core.common.R;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.util.Consts;
import cc.smtweb.framework.core.util.DateUtil;
import cc.smtweb.framework.core.util.NumberUtil;
import cc.smtweb.framework.core.util.StringUtil;
import cc.smtweb.system.bpm.spring.config.FileConfigProperties;
import cc.smtweb.system.bpm.spring.file.attach.AttachHelper;
import cc.smtweb.system.bpm.spring.file.attach.AttachUtil;
import cc.smtweb.system.bpm.util.UtilDownloadFile;
import cc.smtweb.system.bpm.util.UtilFile;
import cc.smtweb.system.bpm.util.UtilLogger;
import cc.smtweb.system.bpm.web.sys.base.attach.AttachInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by AKmm at 11-6-14 上午10:44
 * 附件管理
 */
@Slf4j
@RestController
@RequestMapping("/api/attach")
public class AttachController {
    private static Logger logger = LoggerFactory.getLogger(AttachController.class);
    @Autowired
    private FileConfigProperties properties;
    @Autowired
    private AttachHelper attachHelper;
    @Autowired
    private AttachUtil attachUtil;
    @Autowired
    private DbEngine dbEngine;
    private BASE64Decoder decoder = new BASE64Decoder();

    /**
     * @param request
     * @param type         类型，如idcard：身份证、headImg：头像
     * @param ownerId      拥有者ID
     * @param path         存储目录路径名，如：idcard
     * @param attachIsTemp 是否临时文件：true/false 字符串
     * @param attachName   附件名称，如：XXXXX.jpg
     * @param savePath     保存路径，指定文件保存目录，可为空
     * @return
     * @throws Exception
     */
    @PostMapping({"/upload"})
    public R upload(HttpServletRequest request, @RequestParam(value = "type", required = false) String type,
                    @RequestParam(value = "ownerId", required = false) Long ownerId,
                    @RequestParam(value = "path", required = false) String path,
                    @RequestParam(value = "attachIsTemp", required = false) String attachIsTemp,
                    @RequestParam(value = "attachName", required = false) String attachName,
                    @RequestParam(value = "savePath", required = false) String savePath) throws Exception {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        //判断是否多文件上传
        if (!multipartResolver.isMultipart(request)) {
            return R.error("文件不存在");
        }
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
        Iterator<String> itr = multiRequest.getFileNames();
        MultipartFile file = null;
        while (itr.hasNext()) {
            file = multiRequest.getFile(itr.next());
            AttachInfo attach = new AttachInfo();
            attach.setId(dbEngine.nextId());
            attach.setType(type);//附件类别
            if (null != ownerId) {
                attach.setOwnerId(ownerId);//附件拥有者id
            }
            attach.setPath(path);//附件路径
            attach.setPartyId(-1l);
            attach.setTime(DateUtil.nowDateTimeLong());
            attach.setUserId(-1l);
            attach.setIsTemp("true".equals(attachIsTemp) ? 1: 0);//暂时没有有效拥有者标记 方便定时任务清除垃圾附件
            // 上传文件名
            final int i = file.getOriginalFilename().lastIndexOf(".");
            if (i >= 0) {
                attach.setSuffix(file.getOriginalFilename().substring(i));
            }
            if (StringUtil.isEmpty(attachName)) {
                attachName = file.getOriginalFilename();
            } else {
                attachName = attachName + attach.getSuffix();
            }
            attach.setName(attachName);
            Map<String, Object> ret = new HashMap<>();
            try {
                // 上传文件域对象
                File upload = new File(attachHelper.getAttachTmpPath() + attach.getId() + attach.getSuffix());
                attach.setSize((long) FileCopyUtils.copy(file.getInputStream(), new BufferedOutputStream(new FileOutputStream(upload))));
                if (StringUtil.isEmpty(savePath)) {
                    localSaveAttach(attach, upload);
                } else {//复制到指定目录
                    String filePath;
                    if ("-".equals(savePath)) filePath = upload.getAbsolutePath();
                    else {
                        filePath = savePath + DateUtil.nowDateTimeString() + UtilFile.FSChar + attach.getName();
                        UtilFile.copy(upload, filePath, true);
                    }
                }
            } catch (Exception e) {
                logger.error("上传文件失败", e);
                return R.error("上传文件失败");
            }
            return R.success(attach.getId());
        }
        // 上传文件类型
        //String uploadContentType = file.getContentType();
        return R.error("上传文件失败");
    }

    /**
     * @param request
     * @param response
     * @param base64File   文件base64编码
     * @param attachId     附件ID，可为空，如果有，则替换此附件ID对应数据
     * @param type         类型，如idcard：身份证、headImg：头像
     * @param ownerId      拥有者ID
     * @param path         存储目录路径名，如：idcard
     * @param attachIsTemp 是否临时文件：true/false 字符串
     * @param attachName   附件名称，如：XXXXX.jpg
     * @param savePath     保存路径，指定文件保存目录，可为空
     * @param suffix       文件后缀，如.jpg
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/uploadBase64", method = RequestMethod.POST)
    public R uploadBase64(HttpServletRequest request, HttpServletResponse response,
                          @RequestParam(value = "base64File", required = false) String base64File,
                          @RequestParam(value = "attachId", required = false) Long attachId,
                          @RequestParam(value = "type", required = false) String type,
                          @RequestParam(value = "ownerId", required = false) Long ownerId,
                          @RequestParam(value = "path", required = false) String path,
                          @RequestParam(value = "attachIsTemp", required = false) String attachIsTemp,
                          @RequestParam(value = "attachName", required = false) String attachName,
                          @RequestParam(value = "savePath", required = false) String savePath,
                          @RequestParam(value = "suffix", required = false) String suffix
    ) throws Exception {
//        UtilLogger.error("上传文件接收base64", base64File);
        if (null == base64File || "".equals(base64File)) {
            return R.error("文件不能为空");
        }
        String str[] = base64File.split(",");
        if (str.length > 1) {
            base64File = str[1];
        }
        // 上传文件类型
        //String uploadContentType = file.getContentType();
        AttachInfo attach = null;
        boolean isNew = StringUtil.isEmpty(attachId + "");
        if (isNew) {
            attach = new AttachInfo();
        } else {
            attach = dbEngine.findDao(AttachInfo.class).queryEntity(attachId);
            if (attach == null) {
                attach = new AttachInfo();
                isNew = true;
            } else isNew = attach.isNew();
        }
        attach.setId(attachId);
        if (StringUtil.isEmpty(attachId + "")) attach.setId(dbEngine.nextId());

        attach.setType(type);//附件类别
        if (null != ownerId) {
            attach.setOwnerId(ownerId);//附件拥有者id
        }
        attach.setPath(path);//附件路径
        attach.setPartyId(-1l);
        attach.setTime(DateUtil.nowDateTimeLong());
        attach.setUserId(-1l);
        attach.setIsTemp("true".equals(attachIsTemp) ? 1: 0);//暂时没有有效拥有者标记 方便定时任务清除垃圾附件
        attach.setTime(DateUtil.nowDateTimeLong());
        attach.setIsTemp("true".equals(attachIsTemp) ? 1: 0);//暂时没有有效拥有者标记 方便定时任务清除垃圾附件
        // 上传文件名
        attach.setSuffix(suffix);
        attach.setName(attachName);
        Map<String, Object> ret = new HashMap<>();
        try {
            //将base64转图片存到临时目录
            // 上传文件域对象
            //保存文件
            byte[] byt = decoder.decodeBuffer(base64File);
            for (int i = 0, len = byt.length; i < len; ++i) {
                if (byt[i] < 0) {
                    byt[i] += 256;
                }
            }
            //创建保存目录，格式 类型目录/年月/日
            File upload = new File(attachHelper.getAttachTmpPath() + attach.getId() + attach.getSuffix());
            FileUtils.writeByteArrayToFile(upload, byt);
            attach.setSize(upload.length());
            if (StringUtil.isEmpty(savePath)) {
                localSaveAttach(attach, upload);
            } else {//复制到指定目录
                String filePath;
                if (Consts.NULL_STRING.equals(savePath)) filePath = upload.getAbsolutePath();
                else {
                    filePath = savePath + DateUtil.nowDateTimeString() + UtilFile.FSChar + attach.getName();
                    UtilFile.copy(upload, filePath, true);
                }
            }
        } catch (Exception e) {
            UtilLogger.error("上传文件失败", e);
            return R.error("上传文件失败");
        }
        return R.success(attach.getId());
    }

    @PostMapping({"/copyupload"})
    public R copyupload(HttpServletRequest request) throws Exception {
        String type = request.getParameter("type");
        String attachId = request.getParameter("attachId");
        if (StringUtil.isEmpty(attachId)) {
            return R.success("");
        }
        AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, Long.valueOf(attachId));
        if (null == attach) {
            return R.success("");
        }
        String remoteName = attach.getId() + attach.getName().substring(attach.getName().lastIndexOf("."));
        String remotePath = attach.getPath();
        String filePath = attachHelper.getAttachTmpPath() + "tempFiles/";
        UtilFile.makeDir(filePath);
        Map<String, String> map = null;
        try {
            attachUtil.downloadAttach(remotePath, remoteName, filePath);
            String filePaths = filePath + remoteName;

            attach.setId(dbEngine.nextId());
            attach.setType(type);//附件类别
            attach.setOwnerId(-1l);//附件拥有者id
            attach.setPartyId(-1l);
            attach.setTime(DateUtil.nowDateTimeLong());
            attach.setUserId(-1l);
            attach.setName(attach.getId() + attach.getSuffix());
            // 上传文件域对象
            File upload = new File(filePaths);
//            attach.setSize((long) FileCopyUtils.copy(file.getInputStream(), new BufferedOutputStream(new FileOutputStream(upload))));
            localSaveAttach(attach, upload);
        } catch (Exception e) {
            logger.error("上传文件失败", e);
            return R.error("上传文件失败");
        }
        return R.success(attach.getId());
    }


    //保存处理附件
    private void localSaveAttach(final AttachInfo attach, final File upload) throws Exception {
        try {
            //一般附件，上传到服务器，并记录附件
            //传到ftp服务器上
            attachUtil.saveAttach(attach, upload.getPath(), false);
            //写入数据库
            dbEngine.insertEntity(attach);
        } finally {
            UtilFile.delFile(upload.getAbsolutePath());
        }

    }

    //附件下载
    @RequestMapping(value = "/download", method = {RequestMethod.GET, RequestMethod.POST})
    public R down(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "attachId", required = false) Long attachId) throws Exception {
        AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, attachId);
        if (null == attach) {
            return R.error("附件不存在");
        }
        final String remoteFileName = attach.getName();
        final String fileName = attach.getName();
        final String remotePath = attach.getPath();
        logger.info("下载附件：filePath:" + remotePath + ",fileName:" + fileName);
        try {
            attachUtil.downloadAttach(remotePath, remoteFileName, fileName, response);
            attach.setCount(attach.getCount() + 1);
            dbEngine.updateEntity(attach, "attach_count");
        } catch (Exception e) {
            logger.error("附件下载失败", e);
            R.error("附件下载失败");

        }
        return null;
    }

    //图片附件显示路径
    @GetMapping(value = "/showImg")
    public R showImg(HttpServletResponse response, @RequestParam(value = "attachId", required = false) Long attachId) throws Exception {
        AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, attachId);
        if (null == attach) {
            return R.error("附件不存在");
        }
//        attachUtil.showImg(attach.getPath(),attach.getName(),response);
        attachUtil.downloadAttach(attach.getPath(), attach.getName(), attach.getName(), response);
        return null;
    }

    //图片附件显示路径
    @RequestMapping(value = "/showImgThumb", method = {RequestMethod.GET, RequestMethod.POST})
    public R showImgThumb(HttpServletResponse response, @RequestParam(value = "attachId", required = false) Long attachId,
                          @RequestParam(value = "width", required = false, defaultValue = "200") String width,
                          @RequestParam(value = "height", required = false, defaultValue = "120") String height) throws Exception {
        AttachInfo attach = dbEngine.queryEntity(AttachInfo.class, attachId);
        if (null == attach) {
            return R.error("附件不存在");
        }
        final String remoteFileName = attach.getName();
        final String tempPath = System.getProperty("java.io.tmpdir");
        final String remotePath = attach.getPath();
        try {
            String lfo = tempPath + "/" + remoteFileName;
            String lfd = tempPath + "/thumb_" + attach.getId() + attach.getSuffix();
            attachUtil.downloadAttach(remotePath, remoteFileName, tempPath);
            int w = Integer.valueOf(width);
            int h = Integer.valueOf(height);
            if (w <= 0) w = 100;
            if (h <= 0) h = 100;
            getImgThumb(lfo, lfd, w, h);
            if (UtilFile.isFileExist(lfd)) {
                UtilDownloadFile.downfileEx(response, lfd, attach.getName());
            } else if (UtilFile.isFileExist(lfo)) {
                UtilDownloadFile.downfileEx(response, lfo, attach.getName());
            }
        } catch (Exception e) {
            logger.error("附件下载失败", e);
            R.error("附件下载失败");
        }
        return null;
    }

    private static boolean getImgThumb(String orgFile, String dstFile, int width, int height) {
        BufferedImage bufferedImage;
        try {
            //read image file
            bufferedImage = ImageIO.read(new File(orgFile));

            // create a blank, RGB, same width and height, and a white background
            int w = bufferedImage.getWidth(), h = bufferedImage.getHeight();
            double r = 1;
            if (w > width) {
                r = 1.0 * width / w;
            }

            if (h > height) {
                r = Math.min(1.0 * height / h, r);
            }
            if (!NumberUtil.isEqualsZero(r - 1)) {
                w = (int) Math.round(w * r);
                h = (int) Math.round(h * r);
            }
            BufferedImage newBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

            //TYPE_INT_RGB:创建一个RBG图像，24位深度，成功将32位图转化成24位
            newBufferedImage.createGraphics().drawImage(bufferedImage.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, Color.WHITE, null);
            // write to jpeg file
            ImageIO.write(newBufferedImage, "jpg", new File(dstFile));
            return true;
        } catch (IOException e) {
            logger.error("转换jpg错误：" + orgFile);
            return false;
        }
    }

    //删除附件
    @GetMapping({"/delete"})
    public R del(@RequestParam(value = "attachIds") String attachIds) {
        try {
            List<AttachInfo> attaches = dbEngine.queryWhere(AttachInfo.class, "attach_id in (" + attachIds + ")");
            Assert.isTrue(attaches != null && !attaches.isEmpty(), "附件不存在");
            attaches.forEach(a -> attachHelper.deleteOneAttach(a));
            return R.success("附件删除成功");
        } catch (Exception e) {
            logger.error("删除附件失败", e);
            return R.error(e.getMessage());
        }
    }

    //按拥有者删除附件
    @PostMapping({"/deleteByOwnerId"})
    public R delByOwnerId(HttpServletRequest request, @RequestParam(value = "ownerId", required = false) String ownerId) throws Exception {
        try {
            attachHelper.deleteAttachByOwnerId(ownerId);
            return R.success("附件删除成功");
        } catch (Exception e) {
            logger.error("删除附件失败", e);
            return R.error("删除附件失败");
        }
    }


    //图片附件显示路径
    @GetMapping(value = "/loadAttachBean")
    public R loadAttachBean(@RequestParam(value = "attachIds") String attachIds) throws Exception {
        List<AttachInfo> beans = dbEngine.queryWhere(AttachInfo.class, "attach_id in (" + attachIds + ")");
        return R.success(beans);
    }
}
