package com.sdtool.common.servlet.file;

import com.dySweetFishPlugin.sql.RMapUtils;
import com.sdtool.common.api.LoginService;
import com.sdtool.common.api.SupplierInitService;
import com.sdtool.common.base.BaseHttpServlet;
import com.sdtool.common.base.ERPServlet;
import com.sdtool.common.datas.ERPHeader;
import com.sdtool.common.datas.HttpCode;
import com.sdtool.common.entity.base.BaseEntity;
import com.sdtool.common.entity.site.ERPTokenUser;
import com.sdtool.common.tool.CodeGenerate;
import com.sdtool.common.tool.ERPUtils;
import com.sweetfish.net.WorkThread;
import com.sweetfish.net.http.*;
import com.sweetfish.service.RetResult;
import com.sweetfish.util.AutoLoad;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;

/**
 * Created by jlutt on 2020-07-31
 * 文件上传
 * 公共的文件上传服务，需要自己搞一下用户验证，所以改成从BaseHttpServlet继承算了
 *
 * @author jlutt
 */
@AutoLoad(false)
@WebServlet(value = {"/upload/*"}, comment = "文件上传服务")
@ERPServlet()
public class FileUploadServlet extends BaseHttpServlet {

    @Resource(name = "property.bucketFileRoot")
    private String bucketFileRoot;

    @Resource
    private LoginService loginService;

    @Resource
    private SupplierInitService supplierInitService;

    @Resource
    private CodeGenerate codeGenerate;

    protected ExecutorService getExecutor() {
        Thread thread = Thread.currentThread();
        if (thread instanceof WorkThread) {
            return ((WorkThread) thread).getExecutor();
        }
        return ForkJoinPool.commonPool();
    }

    private final String[] whiteGoodsContentImg = new String[]{".jpg", ".jpeg", ".png", ".webp", ".bmp", ".svg"};

    @Override
    protected void authenticate(HttpRequest request, HttpResponse response) throws IOException {
        ERPTokenUser info = request.currentUser();
        long supplierCode = request.getLongHeader(ERPHeader.HTTPHEADER_SUPPLIER, 0);
        String dataSourceId = request.getHeader(ERPHeader.HTTPHEADER_DATASOURCE, "");

        if (info == null) {
            response.finishJson(RMapUtils.error(HttpCode.UNAUTHORIZED.value(), "未登录"));
            return;
        } else {
            RetResult<BaseEntity> checkResult = loginService.checkUser(info);
            if (!checkResult.isSuccess()) {
                response.finishJson(RMapUtils.error(HttpCode.UNAUTHORIZED.value(), "未登录"));
                return;
            }
        }
        //验证通过调用执行方法
        response.nextEvent();
    }

    /**
     * 使用plupload上传大文件，可分块上传
     * 通用文件上传
     *
     * @param req  http请求
     * @param resp http响应
     * @throws IOException 异常
     */
    @HttpMapping(url = "/upload/bucketFile", auth = true, comment = "通用文件上传")
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public void uploadBucketFile(HttpRequest req, HttpResponse resp) throws IOException {
        ERPTokenUser currentUser = req.currentUser();
        for (MultiPart part : req.multiParts()) {
            //plupload会分块上传，name为文件名，chunks为上传总块数，chunk为当前块数
            //如果chunk=0，表示是第一块，此时需要创建文件，其后是在文件末尾添加内容
            //文件名的处理，如果在服务端生成，那么分块的时候还需要保存实际文件名和随机名的生成关系，处理相对麻烦
            //系统这里使用plupload配置unique_names属性，将会得到一个不重复的文件名

            String srcFileName = req.getParameter("srcfilename");
            String suffix = srcFileName.substring(srcFileName.lastIndexOf("."));
            String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;// req.getParameter("name");

            String bucketName = req.getParameter("bucketName");

            if (StringUtils.isEmpty(bucketName)) {
                resp.finish(500, "文件仓库未指定");
                return;
            }

            int chunks = req.getIntParameter("chunks", 0);
            int chunk = req.getIntParameter("chunk", 0);

            //由于当前orderRoot不在是本地文件夹，先传到本地，再拷贝到
            File destPath = new File(bucketFileRoot + File.separator +
                    currentUser.getSupplierCode() + File.separator +
                    bucketName);
            if (!destPath.exists()) {
                destPath.mkdirs();
            }

            String destFile = destPath.getCanonicalPath() + File.separator + fileName;

            InputStream in = part.getInputStream();

            if ((chunk == 0) && (chunks > 0)) {
                Path destFilePath = Paths.get(destFile);

                if (Files.exists(destFilePath)) {
                    resp.finish(500, "文件已存在");
                    return;
                }

                Files.deleteIfExists(destFilePath);

                ERPUtils.createFileFromInStream(destFile, in);
            } else {
                ERPUtils.appendFileFromInStream(destFile, in);
            }

            String fileLink = bucketName + "/" + fileName;

            if (chunk == chunks - 1) {
                //上传完成
                logger.info("文件上传完成name:" + srcFileName + "总块数:" + req.getParameter("chunks"));
            }

            FileUploadEntity entity = new FileUploadEntity();
            entity.setFileName(fileName);
            entity.setSrcFileName(srcFileName);
            entity.setFileLink(fileLink);

            entity.setUrl(supplierInitService.getFileDownloadUrl(fileLink, "", currentUser.getDataSourceId(), currentUser.getSupplierCode()));
            entity.setWebUrl(supplierInitService.getFileWebDownloadUrl(fileLink, "", currentUser.getDataSourceId(), currentUser.getSupplierCode()));

            //解决前端跨域
            entity.setFileLink("/static/" + currentUser.getSupplierCode() + "/" + fileLink);
            resp.finishJson(entity);
            return;
        }
        resp.finish("success");
    }

    /**
     * wangEditor上传图片，包括产品详情图，网站介绍信息图
     *
     * @param req  http请求
     * @param resp http响应
     * @throws IOException 异常
     */
    @HttpMapping(url = "/upload/wangImage", auth = true, comment = "通用文件上传")
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public void uploadWangImage(HttpRequest req, HttpResponse resp) throws IOException {
        ERPTokenUser currentUser = req.currentUser();

        for (MultiPart part : req.multiParts()) {
            String name = part.getFilename();
            String suffix = name.substring(name.lastIndexOf("."));

            if (StringUtils.isBlank(suffix)) {
                resp.finishJson(WangUploadEntity.newBuilder()
                        .errno(1)
                        .message("文件格式不正确")
                        .build());
            }

            if (Arrays.stream(whiteGoodsContentImg).noneMatch((x) -> x.equalsIgnoreCase(suffix.toLowerCase()))) {
                resp.finishJson(WangUploadEntity.newBuilder()
                        .errno(1)
                        .message("文件格式不正确")
                        .build());
            }

            String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;

            File destPath = new File(bucketFileRoot + File.separator +
                    currentUser.getSupplierCode() + File.separator +
                    "sys_content_image");
            if (!destPath.exists()) {
                destPath.mkdirs();
            }

            String destFile = destPath.getCanonicalPath() + File.separator + fileName;

            part.save(new File(destFile));

            String fileLink = "sys_content_image" + "/" + fileName;
            resp.finishJson(WangUploadEntity.newBuilder()
                    .errno(0)
                    .message("")
                    .data(WangUploadData.newBuilder()
                            .url(supplierInitService.getFileDownloadUrl(fileLink, "", currentUser.getDataSourceId(), currentUser.getSupplierCode()))
                            .build()
                    )
                    .build());
        }
    }
}
