package com.iformall.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.iformall.common.ErrorCode;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.config.AwsProperty;
import com.iformall.domain.po.MallResource;
import com.iformall.domain.po.WxAppinfo;
import com.iformall.exception.MallinkException;
import com.iformall.service.MallResourceService;
import com.iformall.service.QrCodeService;
import com.iformall.service.WxAppinfoService;
import com.iformall.service.wechat.FmOpenService;
import com.iformall.utils.MaUtil;
import com.iformall.utils.QRCodeUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.util.*;

/**
 * @author luozukai
 */
@Service
public class QrCodeServiceImpl implements QrCodeService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private WxAppinfoService wxAppinfoService;
    @Autowired
    private FmOpenService openService;
    @Autowired
    private boolean isFmOpen;
    @Autowired
    private AwsProperty awsProperty;
    @Autowired
    private MallResourceService mallResourceService;
    @Autowired
    private String fmUploadDir;

    private AmazonS3 s3 = null;

    @Override
    public ResultData awsUpload(InputStream inputStream, ObjectMetadata metadata, String fileName, String tenantId) {
        ResultData data = new ResultData();
        try {
            if(s3 == null) {
                s3 = AmazonS3ClientBuilder.standard()
                        .withRegion(awsProperty.getClientRegion())
                        .withCredentials(new AWSCredentialsProvider() {
                            @Override
                            public AWSCredentials getCredentials() {
                                return new BasicAWSCredentials(awsProperty.getAccess(), awsProperty.getSecret());
                            }

                            @Override
                            public void refresh() {

                            }
                        })
                        .build();
            }

            s3.putObject(
                    new PutObjectRequest(awsProperty.getBucketName(), fileName, inputStream, metadata)
                            .withCannedAcl(CannedAccessControlList.PublicRead));
            URL url = s3.getUrl(awsProperty.getBucketName(), fileName);
            logger.info(url.toString());

            MallResource mr = new MallResource();
            mr.setTenantId(tenantId);
            mr.setBucket(awsProperty.getBucketName());
            mr.setS3Key(fileName);
            mr.setUrl(url.toString());
            mallResourceService.saveOrUpdate(mr);

            data.code = ResultData.SUCCESS;
            Map<String, String> map = new HashMap<>();
            map.put("url", url.toString());
            data.data = map;
        } catch (AmazonServiceException ase) {
            data.code = ResultData.ERROR;
            logger.warn("Caught an AmazonServiceException, which " +
                    "means your request made it " +
                    "to Amazon S3, but was rejected with an error response" +
                    " for some reason.");
            logger.warn(ase.getMessage());
            data.code = ResultData.ERROR;
            data.message = "上传失败";
        } catch (AmazonClientException ace) {
            data.code = ResultData.ERROR;
            logger.warn("Caught an AmazonClientException, which " +
                    "means the client encountered " +
                    "an internal error while trying to " +
                    "communicate with S3, " +
                    "such as not being able to access the network.");
            logger.warn("Error Message: " + ace.getMessage());
            data.code = ResultData.ERROR;
            data.message = "上传失败";
        } catch (Exception ioe) {
            data.code = ResultData.ERROR;
            logger.warn("Caught an IOException: " + ioe.getMessage());
            data.code = ResultData.ERROR;
            data.message = "上传失败";
        }
        return data;
    }

    @Override
    public void downQrCode(String tenantId,HttpServletRequest request, HttpServletResponse response, Map<String, Object> params) throws MallinkException {
        String name = (String) params.get("name");
        String pageUrl = (String) params.get("pageUrl");
        String sceneParam = (String) params.get("sceneParam");
        int type = 1;
        try {
            type = (int) params.get("type");
        } catch (Exception e) {
            type = 1;
        }

        int withText = 0;
        try {
            withText = (int) params.get("withText");
        } catch (Exception e) {
            withText = 0;
        }
        String text1 = (String) params.get("text1");
        String text2 = (String) params.get("text2");
        if (StringUtils.isBlank(pageUrl)) {
            throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "pageUrl不能为空");
        }
        try {
            exportQrcode(request, response,
                    tenantId, type, pageUrl, sceneParam,
                    withText, text1, text2,
                    name);
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new MallinkException(Result.ERROR, "下载异常");
        }
    }

    @Override
    public ResultData exportQrcode(HttpServletRequest request, HttpServletResponse response,
                                   String tenantId, int type, String pageUrl, String sceneParam,
                                   int withText, String text1, String text2,
                                   String name) {
        // type 0 有限二维码, 1 无限制二维码
        // withText 0 不带字 1. 带下面的字，2 带下面的两行字
        WxAppinfo appinfo = wxAppinfoService.getCAppInfo(tenantId);
        boolean autoColor = false;
        boolean isHyaline = true;
        WxMaCodeLineColor color = new WxMaCodeLineColor("0", "0", "0");

        WxMaService wxMaService;
        if(isFmOpen) {
            wxMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appinfo.getAppId());
        } else {
            wxMaService = MaUtil.getWeappService(appinfo);
        }

        String pathStr = "";
        if (StringUtils.isNotBlank(sceneParam)) {
            pathStr = pageUrl + "?scene="+sceneParam;
        } else {
            pathStr = pageUrl;
        }


        String filepath = fmUploadDir;
        String fileName = name + ".png";
        String destPath1 = filepath + "1_" + fileName;
        String destPath = filepath + fileName;

        File dest = new File(destPath);
        File pDest = dest.getParentFile();
        if (!pDest.exists()) {
            pDest.mkdirs();
        }
        try {
            if(type == 0) {
                final File codeFile = wxMaService.getQrcodeService().createQrcode(pathStr, QRCodeUtils.QR_WIDTH);
                copyFileToDest(withText, text1, text2, destPath1, dest, codeFile);
                org.apache.commons.io.FileUtils.forceDelete(codeFile);
            } else {
                final File codeFile = wxMaService.getQrcodeService().createWxaCodeUnlimit(sceneParam, pageUrl, QRCodeUtils.QR_WIDTH, autoColor, color, isHyaline);
                copyFileToDest(withText, text1, text2, destPath1, dest, codeFile);
                org.apache.commons.io.FileUtils.forceDelete(codeFile);
            }

        } catch (WxErrorException e) {
            logger.error(e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

        try {
            downFile(destPath, fileName, response, request);
            org.apache.commons.io.FileUtils.forceDelete(dest);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return new ResultData();
    }

    @Override
    public ResultData uploadQrcode(String tenantId, int type, String pageUrl, String sceneParam,
                                   int withText, String text1, String text2,
                                   String name) {
        // type 0 有限二维码, 1 无限制二维码
        // withText 0 不带字 1. 带下面的字，2 带下面的两行字
        WxAppinfo appinfo = wxAppinfoService.getCAppInfo(tenantId);
        boolean autoColor = false;
        boolean isHyaline = true;
        WxMaCodeLineColor color = new WxMaCodeLineColor("0", "0", "0");

        WxMaService wxMaService;
        if(isFmOpen) {
            wxMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appinfo.getAppId());
        } else {
            wxMaService = MaUtil.getWeappService(appinfo);
        }

        String pathStr = "";
        if (StringUtils.isNotBlank(sceneParam)) {
            pathStr = pageUrl + "?scene="+sceneParam;
        } else {
            pathStr = pageUrl;
        }


        String filepath = fmUploadDir;
        String fileName = name + ".png";
        String destPath1 = filepath + "1_" + fileName;
        String destPath = filepath + fileName;

        File dest = new File(destPath);
        File pDest = dest.getParentFile();
        if (!pDest.exists()) {
            pDest.mkdirs();
        }
        try {
            if(type == 0) {
                final File codeFile = wxMaService.getQrcodeService().createQrcode(pathStr, QRCodeUtils.QR_WIDTH);
                copyFileToDest(withText, text1, text2, destPath1, dest, codeFile);
                org.apache.commons.io.FileUtils.forceDelete(codeFile);
            } else {
                final File codeFile = wxMaService.getQrcodeService().createWxaCodeUnlimit(sceneParam, pageUrl, QRCodeUtils.QR_WIDTH, autoColor, color, isHyaline);
                copyFileToDest(withText, text1, text2, destPath1, dest, codeFile);
                org.apache.commons.io.FileUtils.forceDelete(codeFile);
            }

        } catch (WxErrorException e) {
            logger.error(e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

        try {
            //上传
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType("image/jpeg");
            metadata.setContentLength(dest.length());

            FileOutputStream fos = null;
            BufferedInputStream fs = null;

            String fn = UUID.randomUUID().toString();
            int dot = fileName.lastIndexOf('.');
            if (dot >= 0) {
                fn = tenantId + "/" + fn + dest.getName().substring(dot, dest.getName().length());
            } else {
                fn = tenantId + "/" + fn;
            }

            ResultData data = awsUpload(new FileInputStream(dest), metadata, fn, tenantId);
            org.apache.commons.io.FileUtils.forceDelete(dest);
            return data;
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return new ResultData();
    }

    private void copyFileToDest(int withText, String text1, String text2, String destPath1, File dest, File codeFile) throws IOException {
        if (withText == 1) {
            File dest1 = new File(destPath1);
            org.apache.commons.io.FileUtils.copyFile(codeFile, dest1);
            QRCodeUtils.graphicsGeneration(dest1, dest, text1);
            org.apache.commons.io.FileUtils.forceDelete(dest1);
        } else if (withText == 2) {
            File dest1 = new File(destPath1);
            org.apache.commons.io.FileUtils.copyFile(codeFile, dest1);
            QRCodeUtils.graphicsGeneration2(dest1, dest, text1, text2);
            org.apache.commons.io.FileUtils.forceDelete(dest1);
        } else {
            org.apache.commons.io.FileUtils.copyFile(codeFile, dest);
        }
    }

    private void downFile(String filePath, String filename, HttpServletResponse response, HttpServletRequest req) throws IOException {
        try {
            response.reset();
            response.setContentType("application/octet-stream");
            String agent = req.getHeader("user-agent");
            if (agent.contains("Firefox")) {
                response.setHeader("Content-disposition",
                        "attachment; filename="
                                + new String(filename.getBytes("GB2312"),"ISO-8859-1"));
            } else {
                response.setHeader("Content-disposition",
                        "attachment; filename="
                                + java.net.URLEncoder.encode(filename,"UTF-8"));
            }
            // 循环取出流中的数据
            byte[] b = new byte[1024];
            int len;
            InputStream inStream = new FileInputStream(filePath);
            while ((len = inStream.read(b)) > 0)
                response.getOutputStream().write(b, 0, len);
            inStream.close();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }
}
