package com.qmth.jkserver.core.upload;

import com.qmth.jkserver.constant.SpringContextHolder;
import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.exception.ApiException;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.model.Attachment;
import com.qmth.jkserver.service.AttachmentService;
import com.qmth.jkserver.util.FileStoreUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.MultipartConfigElement;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.StringJoiner;
import java.util.UUID;

/**
 * 监考端 远程传输
 * 通用机考优特机考文件上传
 * 添加进度监听
 *
 * @author tianjun
 * 持久化attachmet 并且返回
 */
public class RemoteNormalUtestKjFileUploader implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = -6944438968018096461L;

    private static final Logger LOGGER = LoggerFactory.getLogger(RemoteNormalUtestKjFileUploader.class);

    private HttpServletRequest request;

    private String examCode;

    public RemoteNormalUtestKjFileUploader(HttpServletRequest request, String examCode) {
        this.request = request;
        this.examCode = examCode;
    }

    public Attachment execute() throws IOException, FileUploadException {
        LOGGER.info(".....upload start:" + System.currentTimeMillis() + "......");
        FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        AttachmentService attachmentService = SpringContextHolder.getBean(AttachmentService.class);
        long time1 = System.currentTimeMillis();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        MultipartConfigElement multipartConfigElement = SpringContextHolder.getBean(MultipartConfigElement.class);
        LOGGER.info("-------multipartConfigElement fileSize:" + multipartConfigElement.getMaxFileSize());
        LOGGER.info("-------multipartConfigElement fileRequestSize:" + multipartConfigElement.getMaxRequestSize());
        multipartResolver.setMaxUploadSizePerFile(multipartConfigElement.getMaxFileSize());
        multipartResolver.setMaxUploadSize(multipartConfigElement.getMaxRequestSize());
        long time2 = System.currentTimeMillis();
        LOGGER.info(".....build session CommonsMultipartResolver use :" + (time2 - time1) / 1000 + "s");

        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            if (multipartResolver.isMultipart(request)) {
                MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
                String fileName = multiRequest.getHeader("fileName");
                if (StringUtils.isNotEmpty(fileName)) {
                    fileName = URLDecoder.decode(fileName, SystemConstant.CHARSET_NAME);
                }
                String md5 = multiRequest.getHeader("md5");
                if (StringUtils.isEmpty(md5)) {
                    throw ApiException.PARAM_MD5_MISSING;
                }
                Iterator<String> iter = multiRequest.getFileNames();
                int count = 0;
                while (iter.hasNext()) {
                    if (count > 0) {
                        throw new JkServerException("仅支持单个文件的上传,不支持多文件上传");
                    }
                    count++;
                    MultipartFile file = multiRequest.getFile(iter.next());
                    if (file != null) {
                        // 创建随机文件夹
                        String path = new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + File.separator +
                                SystemConstant.getNanoId();
                        File storeDir = new File(fileStoreConfig.getWorkRoot(), path);
                        if (!storeDir.exists()) {
                            storeDir.mkdirs();
                        }
                        String ext = getExtension(file.getOriginalFilename());
                        String name = SystemConstant.getNanoId() + "." + ext;
                        File saveFile = new File(storeDir, name);
                        saveFile.createNewFile();
                        inputStream = file.getInputStream();
                        outputStream = new FileOutputStream(saveFile);
                        IOUtils.copy(inputStream, outputStream);
                        //检查文件的MD5是否匹配
                        String md5Value = null;
                        if (StringUtils.isNotEmpty(md5)) {
                            md5Value = DigestUtils.md5Hex(new FileInputStream(saveFile));
                            if (!md5Value.equals(md5)) {
                                throw JkServerException.FILE_MD5_NOT_MATCH;
                            }
                        }
                        //2020-12-19日加入上传到阿里云
                        if (fileStoreConfig.workIsOss()) {
                            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getWorkRoot()).add(File.separator).add(path).add(File.separator).add(name);
                            fileStoreConfig.ossUpload(stringJoiner.toString(), file.getInputStream(), md5Value, fileStoreConfig.getWorkRoot());
                            saveFile.delete();
                        }
                        // 存储文件
                        Attachment attachment = new Attachment();
                        attachment.setId(SystemConstant.getDbUuid());
                        attachment.setExamCode(examCode);
                        attachment.setAccessUri(path + File.separator + name);
                        attachment.setPath(path);
                        fileName = StringUtils.isNotEmpty(fileName) ? fileName : file.getOriginalFilename();
                        attachment.setOriginalName(fileName);
                        attachment.setName(name);
                        attachment.setExt(ext);
                        attachment.setExamCode(examCode);
                        attachment.setSize((double) file.getSize());
                        attachment.setTime(System.currentTimeMillis());
//                        if (Objects.isNull(md5Value)) {
//                            md5Value = FileMD5Utils.encrypt(saveFile);
//                        }
                        attachment.setMd5(md5Value);
                        attachment.setMoved(false);
                        LOGGER.info(".....upload end:" + System.currentTimeMillis() + "......");
                        attachmentService.saveOrUpdate(attachment);
//                        attachment = attachmentService.save(attachment);
                        LOGGER.info(".....save uploaded attachment:" + System.currentTimeMillis() + "......");
                        return attachment;
                    } else {
                        throw new JkServerException("文件实体为null导致上传失败");
                    }
                }
            } else {
                throw new JkServerException("上传文件失败,请求中没有检测到文件实体");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                IOUtils.closeQuietly(outputStream);
            }
            if (inputStream != null) {
                IOUtils.closeQuietly(inputStream);
            }
        }
        throw new JkServerException("上传文件失败");
    }

    /**
     * 获取文件的后缀
     */
    protected String getExtension(String fileName) {
        int k = fileName.lastIndexOf(".");
        String ext = "";
        if (k > 0) {
            ext = fileName.substring(k + 1, fileName.length());
        }
        return ext;
    }

    /**
     * @return the request
     */
    public HttpServletRequest getRequest() {
        return request;
    }

    /**
     * @param request the request to set
     */
    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }
}
