package com.hfkj.config;

import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.HttpsUtils;
import com.hfkj.common.utils.RedisUtil;
import com.hfkj.sysenum.WeChatQrCodeActionNameEnum;
import com.hfkj.sysenum.WeChatQrCodeTypeEnum;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import static org.apache.catalina.manager.Constants.CHARSET;

/**
 * @serviceName WeChatQrcodeUtils.java
 * @author Sum1Dream
 * @version 1.0.0
 * @Description // 生成带参数的二维码
 * @createTime 16:11 2022/9/2
 **/
@Slf4j
@Component
public class WeChatQrcodeUtils {

    @Autowired
    private WxMpService wxMpService;

    @Resource
    private RedisUtil redisUtil;

    /**
     * <pre>
     * 创建临时二维码ticket
     * @param sceneId       场景值ID，临时二维码时为32位非0整型
     * @param expireSeconds 该二维码有效时间，以秒为单位。 最大不超过2592000（即30天），此字段如果不填，则默认有效期为30秒。
     * @auther: cao_wencao
     * @date: 2019/2/18 16:58
     * </pre>
     */
    public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException {
        WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(sceneId, expireSeconds);
        return wxMpQrCodeTicket;
    }

    /**
     * <pre>
     * 创建临时二维码ticket
     * @param sceneStr      场景值ID（字符串形式的ID），字符串类型，长度限制为1到64
     * @param expireSeconds 该二维码有效时间，以秒为单位。 最大不超过2592000（即30天），此字段如果不填，则默认有效期为30秒。
     * @auther: cao_wencao
     * @date: 2019/2/18 17:01
     * </pre>
     */
    public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException {
        WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(sceneStr, expireSeconds);
        return wxMpQrCodeTicket;
    }

    /**
     * <pre>
     * 创建永久二维码ticket
     * @param sceneId 场景值ID，最大值为100000（目前参数只支持1--100000）
     * @auther: cao_wencao
     * @date: 2019/2/18 17:03
     * </pre>
     */
    public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException {
        return wxMpService.getQrcodeService().qrCodeCreateLastTicket(sceneId);
    }

    /**
     * <pre>
     * 创建永久字符串二维码ticket
     * @param sceneStr 参数。字符串类型长度现在为1到64
     * @auther: cao_wencao
     * @date: 2019/2/18 17:05
     * </pre>
     */
    public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException {
        return wxMpService.getQrcodeService().qrCodeCreateLastTicket(sceneStr);
    }

    // 创建微信二维码
    public JSONObject createWxQrCode(String token,String sceneStr , String actionName) {
        JSONObject object = new JSONObject();
        JSONObject objectScene = new JSONObject();
        JSONObject objectActionInfo = new JSONObject();
        objectScene.put("scene_str" , sceneStr);
        objectActionInfo.put("scene" , objectScene);
        object.put("action_name" , actionName);
        object.put("expire_seconds" , 2592000);
        object.put("action_info" , objectActionInfo);
        return HttpsUtils.doPost("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + token, object);
    }


    // 获取微信Token存入redis
    public String  getWxToken() {
        Object token = redisUtil.get("WxToken");
        if (null != token) {
            return token.toString();
        };
        // 获取access_token
        Map<String, Object> params = new HashMap<>();
        params.put("appid", CommonSysConst.getSysConfig().getWechat_mp_appid());
        params.put("secret", CommonSysConst.getSysConfig().getWechat_mp_secret());
        params.put("grant_type", "client_credential");
        JSONObject accessTokenObject = HttpsUtils.doGet("https://api.weixin.qq.com/cgi-bin/token", params);
        redisUtil.set("WxToken" , accessTokenObject.getString("access_token") , 7000);
        return accessTokenObject.getString("access_token");
    }

    /**
     * <pre>
     * 换取二维码图片文件，jpg格式
     * @param ticket 二维码ticket
     * @auther: cao_wencao
     * @date: 2019/2/18 17:07
     * </pre>
     */
    public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException {
        return wxMpService.getQrcodeService().qrCodePicture(ticket);

    }

    /**
     * <pre>
     * 换取二维码图片url地址（可以选择是否生成压缩的网址）
     * @param ticket       二维码ticket
     * @param needShortUrl 是否需要压缩的二维码地址
     * @auther: cao_wencao
     * @date: 2019/2/18 17:10
     * </pre>
     */
    public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException {
        String qrCodeUrl = wxMpService.getQrcodeService().qrCodePictureUrl(ticket, needShortUrl);
        return qrCodeUrl;
    }

    /**
     * <pre>
     * 换取二维码图片url地址
     * @param ticket 二维码ticket
     * @auther: cao_wencao
     * @date: 2019/2/18 17:11
     * </pre>
     */
    public String qrCodePictureUrl(String ticket) throws WxErrorException {
        String url = wxMpService.getQrcodeService().qrCodePictureUrl(ticket);
        return url;
    }


    /**
     * 处理 subscribe 类型的event
     *
     * @param map
     * @return
     */
    public String handleEventSubscribe(Map<String, String> map) {
        String resXmlStr = getReturnMsgSubscribe(map);
        return resXmlStr;
    }


    /**
     * @Author Sum1Dream
     * @Name getReturnMsgSubscribe
     * @Description // 处理文本
     * @Date 16:34 2022/9/21
     * @Param [decryptMap]
     * @Return java.lang.String
     */
    public String getReturnMsgSubscribe(Map<String, String> decryptMap) {
        TextMessage textMessage = new TextMessage();
        textMessage.setToUserName(decryptMap.get("FromUserName"));
        textMessage.setFromUserName(decryptMap.get("ToUserName"));
        textMessage.setCreateTime(System.currentTimeMillis());
        textMessage.setMsgType("text");
        textMessage.setContent(decryptMap.get("content"));
        return getXmlString(textMessage);
    }

    /**
     * @Author Sum1Dream
     * @Name getXmlString
     * @Description // 处理xml文件
     * @Date 16:34 2022/9/21
     * @Param [textMessage]
     * @Return java.lang.String
     */
    public String getXmlString(TextMessage textMessage) {
        String xml = "";
        if (textMessage != null) {
            xml = "<xml>";
            xml += "<ToUserName><![CDATA[";
            xml += textMessage.getToUserName();
            xml += "]]></ToUserName>";
            xml += "<FromUserName><![CDATA[";
            xml += textMessage.getFromUserName();
            xml += "]]></FromUserName>";
            xml += "<CreateTime>";
            xml += textMessage.getCreateTime();
            xml += "</CreateTime>";
            xml += "<MsgType><![CDATA[";
            xml += textMessage.getMsgType();
            xml += "]]></MsgType>";
            xml += "<Content><![CDATA[";
            xml += textMessage.getContent();
            xml += "]]></Content>";
            xml += "</xml>";
        }
        return xml;
    }

    /**
     * @Author Sum1Dream
     * @Name paramPars
     * @Description // 微信二维码参数解析
     * @Date 13:50 2022/9/22
     * @Param [param]
     * @Return com.alibaba.fastjson.JSONObject
     */
    public JSONObject paramPars(String param) {
        String[] paramArray = param.split("&");
        JSONObject object = new JSONObject();
        for (String s : paramArray) {
            String[] array = s.split("=");
            object.put(array[0] , array[1]);
        }
        return object;
    }

    /**
     * @Author Sum1Dream
     * @Name downloadQrCode
     * @Description // 下载微信二维码到本地
     * @Date 15:03 2023/3/8
     * @Param [wxQrUrl]
     * @Return java.lang.String
     */
    public  String downloadQrCode(String wxQrUrl) throws Exception {
        //定义一个URL对象，就是你想下载的图片的URL地址
        URL urld = new URL(wxQrUrl);
        //打开连接
        HttpURLConnection conn = (HttpURLConnection) urld.openConnection();
        //设置请求方式为"GET"
        conn.setRequestMethod("GET");
        //超时响应时间为10秒
        conn.setConnectTimeout(10 * 1000);
        //通过输入流获取图片数据
        InputStream is = conn.getInputStream();
        //得到图片的二进制数据，以二进制封装得到数据，具有通用性
        byte[] data = readInputStream(is);
        //创建一个文件对象用来保存图片，默认保存当前工程根目录
        String downloadQrCodeImgUrl = CommonSysConst.getSysConfig().getFile_url() + "/downloadQrCodeImg.jpg";
        File imageFile = new File(downloadQrCodeImgUrl);
        //创建输出流
        FileOutputStream outStream = new FileOutputStream(imageFile);
        //写入数据
        outStream.write(data);
        //关闭输出流，释放资源
        outStream.close();
        return downloadQrCodeImgUrl;
    }

    /**
     * @Author Sum1Dream
     * @Name decoderQRCode
     * @Description // 解析二维码内容
     * @Date 15:06 2023/3/8
     * @Param [downloadQrCodeImgUrl]
     * @Return java.lang.String
     */
    public String decoderQRCode(String downloadQrCodeImgUrl) throws Exception {
        BufferedImage image;
        image = ImageIO.read(new File(downloadQrCodeImgUrl));
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        QRCodeReader reader = new QRCodeReader();
        result = reader.decode(bitmap, hints);

        return result.getText();
    }

    /**
     * @Author Sum1Dream
     * @Name readInputStream
     * @Description // 读取插入内容
     * @Date 15:03 2023/3/8
     * @Param [inStream]
     * @Return byte[]
     */
    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        //创建一个Buffer字符串
        byte[] buffer = new byte[6024];
        //每次读取的字符串长度，如果为-1，代表全部读取完毕
        int len;
        //使用一个输入流从buffer里把数据读取出来
        while ((len = inStream.read(buffer)) != -1) {
            //用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
            outStream.write(buffer, 0, len);
        }
        //关闭输入流
        inStream.close();
        //把outStream里的数据写入内存
        return outStream.toByteArray();
    }

    /**
     * 生成微信二维码链接
     * @param code 参数
     * @return
     */
    public String generateQrCodeImgUrl(String token, WeChatQrCodeTypeEnum codeTypeEnum, String code, WeChatQrCodeActionNameEnum actionNameEnum) {
        // 组装 二维码参数
        String sceneId = "type=4&codeType="+codeTypeEnum.getCode()+"&code=" + code;
        // 获取二维码参数
        JSONObject response = createWxQrCode(token, sceneId , actionNameEnum.getName());
        if (StringUtils.isBlank(response.getString("url"))) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "生成失败");
        }
        return response.getString("url");
    }

}
