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.model.ExamCode;
import com.qmth.jkserver.model.ExamPlan;
import com.qmth.jkserver.service.AttachmentService;
import com.qmth.jkserver.service.JkExamPlanService;
import com.qmth.jkserver.util.FileStoreUtil;
import org.apache.commons.codec.digest.DigestUtils;
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.*;

/**
 * 文件上传
 *
 * @author tianjun
 * 持久化attachmet 并且返回
 */
public class FileUploader implements Serializable {

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

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

    private HttpServletRequest request;

    private String examCode;

    private String md5;

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

    public FileUploader(HttpServletRequest request) {
        this.request = request;
    }

    public List<Attachment> execute() throws IOException {
        FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        AttachmentService attachmentService = SpringContextHolder.getBean(AttachmentService.class);
        JkExamPlanService examPlanService = SpringContextHolder.getBean(JkExamPlanService.class);
        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());
        List<Attachment> results = new ArrayList<Attachment>();
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            if (multipartResolver.isMultipart(request)) {
                MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
                examCode = StringUtils.isEmpty(examCode) ? multiRequest.getHeader("examCode") : examCode;
                if (StringUtils.isEmpty(examCode)) {
                    throw ApiException.EXAM_CODE_INVALID;
                }
                ExamCode checkExamCode = examPlanService.findExamCode(examCode);
                ExamPlan examPlan = examPlanService.findByExamCode(examCode);
                if (checkExamCode != null && checkExamCode.getUsed() && examPlan == null) {
                    throw ApiException.EXAM_CODE_INVALID;
                }
                if (checkExamCode.getUsed() && !examPlan.getEnable()) {
                    throw ApiException.EXAM_PLAN_DISABLED;
                }
//			if(checkExamCode.isUsed() && !ExamStatus.PUBLISHED.equals(examPlan.getExamStatus())){
//				throw ApiException.EXAM_PLAN_UN_PUBLISHED;
//			}
                md5 = multiRequest.getHeader("md5");
                String fileName = multiRequest.getHeader("fileName");
                if (StringUtils.isNotEmpty(fileName)) {
                    fileName = URLDecoder.decode(fileName, SystemConstant.CHARSET_NAME);
                }
                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);
                        System.out.println("path:" + saveFile.getAbsolutePath());
                        saveFile.createNewFile();
                        inputStream = file.getInputStream();
                        outputStream = new FileOutputStream(saveFile);
                        IOUtils.copy(inputStream, outputStream);
                        //检查文件的MD5是否匹配
                        String md5Value = DigestUtils.md5Hex(new FileInputStream(saveFile));
                        if (StringUtils.isNotEmpty(md5)) {
//                            md5Value = FileMD5Utils.encrypt(saveFile);
                            if (!md5Value.equals(md5)) {
                                throw JkServerException.FILE_MD5_NOT_MATCH;
                            }
                        }
                        // 存储文件
                        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);
//                        attachment = attachmentService.save(attachment);
                        attachmentService.saveOrUpdate(attachment);
                        results.add(attachment);
                        IOUtils.closeQuietly(outputStream);
                        IOUtils.closeQuietly(inputStream);
                        //2020-12-19日加入上传到阿里云
                        if (fileStoreConfig.workIsOss()) {
                            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getWorkRoot()).add(File.separator).add(path).add(File.separator).add(name);
                            String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
                            fileStoreConfig.ossUpload(dirName, file.getInputStream(), md5Value, fileStoreConfig.getWorkRoot());
                            saveFile.delete();
                        }
                        System.out.println("save file:" + saveFile.getAbsolutePath());
                    } else {
                        throw new JkServerException("文件实体为null导致上传失败,考试识别码:" + examCode);
                    }
                }
            } else {
                throw new JkServerException("上传文件失败,请求中没有检测到文件实体,考试识别码:" + examCode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                IOUtils.closeQuietly(outputStream);
            }
            if (inputStream != null) {
                IOUtils.closeQuietly(inputStream);
            }
        }
        return results;
    }

    /**
     * 获取文件的后缀
     */
    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;
    }

    /**
     * @return the examCode
     */
    public String getExamCode() {
        return examCode;
    }

    /**
     * @param examCode the examCode to set
     */
    public void setExamCode(String examCode) {
        this.examCode = examCode;
    }

    /**
     * @return the md5
     */
    public String getMd5() {
        return md5;
    }

    /**
     * @param md5 the md5 to set
     */
    public void setMd5(String md5) {
        this.md5 = md5;
    }


}
