package com.tzld.piaoquan.growth.common.utils;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @description: 生成二维码
 * @author： TanJingyu
 * @create：2023-06-12 11:17:01
 **/
public class QrCodes {
    private static final Logger logger = LoggerFactory.getLogger(QrCodes.class);
    /**
     * 定义二维码图片的宽度
     */
    public static final int DEFAULT_WIDTH = 500;
    /**
     * 定义二维码图片的高度
     */
    public static final int DEFAULT_HEIGHT = 500;
    /**
     * 定义LOGO图片的宽度
     */
    public static final int DEFAULT_LOGO_WIDTH = 100;
    /**
     * 定义LOGO图片的高度
     */
    public static final int DEFAULT_LOGO_HEIGHT = 100;
    /**
     * 定义二维码的边距，默认一个单位
     */
    public static final int DEFAULT_MARGIN = 1;
    /**
     * 定义二维码生成后的预估大小，越准确的设置，越能避免byteArrayOutPutStream中数组的多次扩容
     */
    public static final int DEFAULT_ESTIMATE_SIZE = 9216;
    /**
     * 定义编码
     */
    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    /**
     * 定义二维码图像的后缀
     */
    public static final String DEFAULT_FORMAT = "png";


    public static String createForBase64Str(String url) {
        return createForBase64Str(url, null);
    }

    public static String createForBase64Str(String url, String logoLocation) {
        return createForBase64Str(url, logoLocation, DEFAULT_FORMAT, DEFAULT_HEIGHT, DEFAULT_WIDTH, DEFAULT_LOGO_WIDTH, DEFAULT_LOGO_HEIGHT, DEFAULT_MARGIN, DEFAULT_ESTIMATE_SIZE, DEFAULT_CHARSET);
    }


    /**
     * 前后端分离模式,推荐将二维码图片的二进制数组经base64成字符串返回给前端，这样有时可以避免前端再次请求后端
     *
     * @param url          二维码的真实地址
     * @param logoLocation 二维码中间logo在后端项目中的位置，resource下边
     * @param format       生成二维码的图片格式
     * @param height       二维码图片的高度
     * @param width        二维码图片的宽度
     * @param logoWidth    中间logo宽度
     * @param logoHeight   中间logo高度
     * @param margin       二维码图片边距
     * @param estimateSize 估计二维码图片的大小会是多大？越精准的估计，越能避免byteArrayOutPutStream中缓存数组的扩容
     * @param charset      编码
     */
    public static String createForBase64Str(String url, String logoLocation, String format, int height, int width, int logoWidth, int logoHeight, int margin, int estimateSize, Charset charset) {
        try {
            /*生成二维码*/
            // 定义Map集合封装二维码配置信息
            Map<EncodeHintType, Object> hints = new HashMap<>();
            // 设置二维码图片的内容编码
            hints.put(EncodeHintType.CHARACTER_SET, charset.displayName());
            // 设置二维码图片的上、下、左、右间隙
            hints.put(EncodeHintType.MARGIN, margin);
            // 设置二维码的纠错级别
            hints.put(EncodeHintType.ERROR_CORRECTION,
                    ErrorCorrectionLevel.H);
            //创建二维码字节转换对象
            //第一个参数：二维码图片中的内容
            //第二个参数：二维码格式器
            //第三个参数：生成二维码图片的宽度
            //第四个参数：生成二维码图片的高度
            //第五个参数：生成二维码需要配置信息
            BitMatrix matrix = new
                    MultiFormatWriter().encode(url,
                    BarcodeFormat.QR_CODE, width, height, hints);



            /*生成放置二维码和中间logo的底图,并将二维码画上去*/
            // 获取二维码图片真正的宽度
            int matrix_width = matrix.getWidth();
            // 获取二维码图片真正的高度
            int matrix_height = matrix.getHeight();
            // 定义一张空白的缓冲流图片
            BufferedImage image = new
                    BufferedImage(matrix_width, matrix_height,
                    BufferedImage.TYPE_INT_RGB);
            // 把二维码字节转换对象 转化 到缓冲流图片上
            for (int x = 0; x < matrix_width; x++) {
                for (int y = 0; y < matrix_height; y++) {
                    // 通过x、y坐标获取一点的颜色 true: 黑色  false: 白色
                    int rgb = matrix.get(x, y) ? 0x000000 : 0xFFFFFF;
//                    int rgb = matrix.get(x, y) ? 0x008000 : 0xFFFFFF;
                    image.setRGB(x, y, rgb);
                }
            }



            /*处理logo,把logo画到底图中间*/
            InputStream logoStream = null;
            if (StringUtils.isNotBlank(logoLocation)) {
                logoStream = QrCodes.class.getClassLoader().getResourceAsStream(logoLocation);
                if (Objects.isNull(logoStream)) {
                    logger.warn("生成二维码失败,未找到logo图");
                    return "";
                }
            }
            if (Objects.nonNull(logoStream)) {
                BufferedImage logo = ImageIO.read(logoStream);
                // 获取缓冲流图片的画笔
                Graphics2D g = (Graphics2D) image.getGraphics();
                // 在二维码图片中间绘制公司logo
                g.drawImage(logo, (matrix_width - logoWidth) / 2,
                        (matrix_height - logoHeight) / 2,
                        logoWidth, logoHeight, null);

                // 设置画笔的颜色
                g.setColor(Color.WHITE);
                // 设置画笔的粗细
                g.setStroke(new BasicStroke(5.0f));
                // 设置消除锯齿
                g.setRenderingHint(RenderingHints
                        .KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                // 绘制圆角矩形
                g.drawRoundRect((matrix_width - logoWidth) / 2,
                        (matrix_height - logoHeight) / 2,
                        logoWidth, logoHeight, 10, 10);
            }


            /*base64字符串返回图片*/
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(estimateSize);
            ImageIO.write(image, format, byteArrayOutputStream);
            return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
        } catch (Exception e) {
            logger.error("生成二维码出错: {}", e.getMessage());
            e.printStackTrace();
            return "";
        }
    }

    public static String checkQRCode(String filePath){
        long start = System.currentTimeMillis();
        try {
            // 读取二维码图片到缓冲区
            BufferedImage image = ImageIO.read(new File(filePath));
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
            Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
            hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
            Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码
            logger.info("checkQRCode ======>>encode Type： " + result.getBarcodeFormat() + " ======>>content：" + result.getText());
            return result.getText();
        } catch (Exception e) {
            logger.error("checkQRCodeError" + e.getMessage());
            return null;
        }
    }

    public static String downloadAndCheckQRCode(String url, String filePath) {
        try {
            File image = new File(filePath);
            downloadFile(url, image);
            return QrCodes.checkQRCode(filePath);
        } catch (Exception e) {
            logger.error("downloadAndCheckQRCode Error url:{} cost:{}", url, e);
        } finally {
            FileUtils.deleteFileByIO(filePath);
        }
        return null;
    }

    public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {
        Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        return outputImage;
    }

    public static void downloadFile(String url, File file) throws Exception {
        Request request = new Request.Builder()
                .url(url)
                .build();
        OkHttpClient client = new OkHttpClient().newBuilder()
                .connectTimeout(3, TimeUnit.MINUTES)
                .readTimeout(1, TimeUnit.MINUTES)
                .writeTimeout(1, TimeUnit.MINUTES).build();
        Call call = client.newCall(request);
        Response response = call.execute();
        InputStream is = response.body().byteStream();
        FileOutputStream outputStream = new FileOutputStream(file);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        is.close();
    }




    public static void main(String[] args) {
        String filePath = "/Users/wangyunpeng/IdeaProjects/aigc-admin/datalog/weblog/aigc-admin/";
        String fileName = BaseUtils.getUUIDStr();
        try {
            File image = new File(filePath + fileName);
            downloadFile("https://mmbiz.qpic.cn/sz_mmbiz_png/rGQMLMianRiaZgicELeh23DhLhjTTY2BPRqp3OwGDtXIAp7Za75iazicK29p2LKfnjdZVRsgyTkXASdttsINd9erkew/640?wx_fmt=png&from=appmsg", image);
            System.out.println(QrCodes.checkQRCode(filePath + fileName));
        } catch (Exception e) {

        } finally {
//            FileUtils.deleteFileByIO(filePath + fileName);
        }
    }
}

    