package com.zhiqiyun.open.mvc.controller;


import com.zhiqiyun.open.annotation.Permission;
import com.zhiqiyun.open.core.models.UploadResult;
import com.zhiqiyun.open.core.models.statistics.UploadFileInfo;
import com.zhiqiyun.open.core.service.SequenceService;
import com.zhiqiyun.open.core.service.UploadFileInfoService;
import com.zhiqiyun.open.exception.UploadException;
import com.zhiqiyun.open.mvc.Result;
import com.zhiqiyun.open.mvc.params.UploaderBase64Param;
import com.zhiqiyun.open.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Slf4j
@RestController
@RequestMapping
public class UploaderController {

    @Value("${uploader.max-size}")
    private long maxSize;

//	@Value("${uploader.file-host}")
//	private String fileHost;

    @Value("${uploader.allow-file-types}")
    private String[] allowExtensions;

    @Value("${uploader.save-path}")
    private String savePath;

    @Autowired
    private UploadFileInfoService uploadFileInfoService;

    @Autowired
    private SequenceService sequenceService;


    @Permission(tags = "上传图片", writeLog = false)
    @PostMapping(value = "/uploader/handle/base64File")
    public Object handleBase64File(@RequestBody UploaderBase64Param param) throws IOException {

        if (StringUtils.isBlank(param.getBase64File())) {
            log.warn("没有添加上传文件");
            return Result.instance("没有添加上传文件");
        }
        byte[] fileBuff = Base64.decodeBase64(param.getBase64File());

        String originalFilename = param.getFilename();
        if (StringUtils.isBlank(originalFilename)) {
            originalFilename = String.format("%s.%s", DigestUtils.md5Hex(fileBuff), "png");
        }

        UploadResult uploadResult = this.handle(originalFilename, fileBuff);
        if (uploadResult.isSuccess()) {
            return Result.instance(Result.Code.SUCCESS).setData(uploadResult);
        } else {
            return Result.instance(Result.Code.MESSAGE_ERROR, uploadResult.getMessage());
        }
    }

    public UploadResult handle(String originalFilename, byte[] fileBuff) {
        UploadResult result = new UploadResult();
        result.setSuccess(false);
        result.setOriginalFileName(originalFilename);
        try {
            // 验证文件件大小
            if (fileBuff.length > maxSize * 1024) {
                throw new UploadException("上传文件大小不能超过" + (maxSize / 1024) + "M");
            }

            MagicMatch magicMatch = Magic.getMagicMatch(fileBuff);

            String extension = magicMatch.getExtension();
            String mimeType = magicMatch.getMimeType();

            // 验证文件类型
            if (extension == null) {
                throw new UploadException("无的文件扩展名，请重新上传");
            }

            extension = extension.toLowerCase();
            List<String> listAllowExtensions = Arrays.asList(allowExtensions);
            if (!listAllowExtensions.contains(extension)) {
                throw new UploadException(String.format("只能上传%s类型的文件", String.join(",", allowExtensions)));
            }

            String filePath = String.format("%s/%s", savePath, DateUtil.format("yyyy/MM/dd"));
            File fileDir = new File(filePath);
            if (!fileDir.exists()) {
                boolean mkdirResult = fileDir.mkdirs();
                if (!mkdirResult) {
                    log.warn("mkdir save file path error {}", filePath);
                    throw new UploadException("创建上传目录失败");
                }
            }
            filePath = String.format("%s/%s.%s", filePath, DigestUtils.md5Hex(fileBuff), extension);
            File file = new File(filePath);


            try {
                ByteArrayInputStream in = new ByteArrayInputStream(fileBuff);
                BufferedImage bi = ImageIO.read(in);
                Thumbnails.of(bi).size(1200, 1200).toFile(file);
            } catch (IOException e) {
                log.warn("upload is not image file", e);
                throw new UploadException("只能上传图片文件");
            }

            result.setSuccess(true);
            result.setMessage("上传文件成功");
            result.setMimeType(mimeType);
            // 获取服务地址和端口
            String url = filePath.replaceFirst(this.savePath, "");
            result.setSrc(url);
            result.setSize(fileBuff.length);
            result.setExtension(extension);
            result.setId(this.sequenceService.nextId());

            UploadFileInfo fileInfo = new UploadFileInfo();
            BeanUtils.copyProperties(result, fileInfo);
            fileInfo.setCreatedTime(DateUtil.current());
            this.uploadFileInfoService.save(fileInfo);
        } catch (UploadException e) {
            result.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("upload file error", e);
            result.setMessage("服务异常，请稍后再试");
        }
        return result;
    }
}
