package com.yeejoin.equipmanage.common.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.yeejoin.amos.boot.biz.common.utils.SecureRandomUtil;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Hashtable;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 二维码工具类
 *
 * @author Administrator
 */
public class QRCodeUtil {

    private static Random random = new Random();

    private static final String CHARSET = "utf-8";

    private static final String PREFIX_EQUIPMENT = "AMOS#PATROL#01#";  //平台#子系统#分类编码#

    private static final int QRCODE_SIZE = 45;

    private static int randomNumForQrCode;

    /**
     * <pre>
     * 根据当前记录ID生成QRCode
     * </pre>
     *
     * @return
     */
    public static String generateQRCode(Date dateCreated, String pointNo) {
        return String.valueOf(dateCreated.getTime() + pointNo);
    }


    /**
     * <pre>
     * 生成QRCode
     * </pre>
     *
     * @param id
     * @return
     */
    public static String generateQRCode() {
        String res;
        //加锁生成随机数，保证自增后释放
        Lock lock = new ReentrantLock();
        lock.lock();
        randomNumForQrCode += 1;
        //return String.valueOf(dateCreated.getTime() + id);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        try {
            res = simpleDateFormat.format(new Date(System.currentTimeMillis())).substring(5, 8) + String.valueOf(IdWorker.getFlowIdWorkerInstance().nextId()).substring(0, 10) + randomNumForQrCode;
        } catch (Exception e) {
            SecureRandom random = new SecureRandom();
            String tmp = "";
            for (int i = 0; i < 13; i++) {
                tmp += SecureRandomUtil.getIntSecureRandom(10, random);
            }
            res = simpleDateFormat.format(new Date(System.currentTimeMillis())).substring(2, 8) + tmp.substring(0, 10) + randomNumForQrCode;
        } finally {
            lock.unlock();
        }
        return res;
    }


    /**
     * 生成临时的qrCode
     *
     * @return
     */
    public static String temporaryQrCode() {
        long qrCode = -1 * System.currentTimeMillis();
        qrCode += (long) (SecureRandomUtil.getIntSecureRandomByDouble() * 10000000);
        return String.valueOf(qrCode);
    }

    /**
     * 根据二维码信息，生成二维码图片 用户excel，word等导出图片
     *
     * @param content
     * @return
     */
    public static byte[] generateQRCodeImageByteData(String content) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.MARGIN, 1);
            BitMatrix bitMatrix = new MultiFormatWriter().encode(
                    /*PREFIX_EQUIPMENT + */content
                    , BarcodeFormat.QR_CODE
                    , QRCODE_SIZE
                    , QRCODE_SIZE,
                    hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
            ImageIO.write(image, "png", out);
            return out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 生成简单的二维码
     *
     * @param text   二维码内容
     * @param width  二维码宽度
     * @param height 二维码高度
     * @return String 图片base64
     */
    public static String genQrCodeBase64Png(String text, int width, int height) {
        ByteArrayOutputStream outputStream;
        Base64.Encoder encoder;
        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
            outputStream = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream);
            encoder = Base64.getEncoder();
        } catch (Exception e) {
            throw new RuntimeException("二维码生成失败");
        }
        return encoder.encodeToString(outputStream.toByteArray());
    }

    /**
     * 生成带文字说明的二维码
     *
     * @param text       二维码内容
     * @param width      二维码宽度
     * @param height     二维码高度
     * @param word       二维码下方文字说明
     * @param wordHeight 二维码下方文字高度
     * @return String 图片base64
     */
    public static String genQrCodeBase64PngWithWord(String text, int width, int height, String word, int wordHeight) {
        return genQrCodeBase64PngWithWord(text, width, height, word, wordHeight, -1);
    }

    /**
     * 生成带文字说明的二维码
     *
     * @param text       二维码内容
     * @param width      二维码宽度
     * @param height     二维码高度
     * @param word       二维码下方文字说明
     * @param wordHeight 二维码下方文字高度
     * @return String 图片base64
     */
    public static String genQrCodeBase64PngWithWord(String text, int width, int height, String word, int wordHeight, int type) {
        ByteArrayOutputStream outputStream;
        Base64.Encoder encoder;
        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
            BufferedImage image = type == -1 ? MatrixToImageWriter.toBufferedImage(bitMatrix) : toBufferedImage(bitMatrix, type);
            BufferedImage outImage = null;
            if (StringUtils.isNotBlank(word)) {
                outImage = new BufferedImage(width, wordHeight, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg = outImage.createGraphics();
                // 画二维码到新的面板
                outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
                // 画文字到新的面板
                outg.setColor(Color.BLACK);
                // 字体、字型、字号
                outg.setFont(new Font("微软雅黑", Font.PLAIN, 16));
                int strWidth = outg.getFontMetrics().stringWidth(word);
                int singleFd = outg.getFontMetrics().stringWidth("2");
                int grow = width / singleFd - 1;
                //长度过长就截取超出二维码宽度部分换行
                if (strWidth > width) {
                    String serialNum1 = word.substring(0, grow);
                    String serialNum2 = word.substring(grow);
                    outg.drawString(serialNum1, 5, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2);
                    BufferedImage outImage2 = new BufferedImage(width, wordHeight, BufferedImage.TYPE_4BYTE_ABGR);
                    Graphics2D outg2 = outImage2.createGraphics();
                    outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
                    outg2.setColor(Color.BLACK);
                    // 字体、字型、字号
                    outg2.setFont(new Font("微软雅黑", Font.PLAIN, 16));
                    //参数：显示的内容、起始位置x、起始的y
                    outg2.drawString(serialNum2, 5, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2);
                    outg2.dispose();
                    outImage2.flush();
                    outImage = outImage2;
                } else {
                    // 画文字
                    outg.drawString(word, (width - strWidth) / 2, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 3);
                }
                outg.dispose();
                outImage.flush();
                image.flush();
            }
            outputStream = new ByteArrayOutputStream();
            ImageIO.write(outImage, "PNG", outputStream);
            encoder = Base64.getEncoder();
        } catch (Exception e) {
            throw new RuntimeException("二维码生成失败");
        }
        return encoder.encodeToString(outputStream.toByteArray());
    }

    /**
     * 根据二维码信息，生成二维码图片 用户excel，word等导出图片  可自定义图片大小
     *
     * @param content
     * @return
     */
    public static byte[] generateQRCodeImageByteData(String content, int size) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.MARGIN, 1);
            BitMatrix bitMatrix = new MultiFormatWriter().encode(
                    content
                    , BarcodeFormat.QR_CODE
                    , size
                    , size,
                    hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
            ImageIO.write(image, "png", out);
            return out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * image流数据处理
     */
    private static BufferedImage toBufferedImage(BitMatrix matrix, Integer type) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (1 == type) {
                    // 红色
                    image.setRGB(x, y, matrix.get(x, y) ? 0xDD4747 : 0xFFFFFFFF);
                } else if (2 == type) {
                    // 黄色
                    image.setRGB(x, y, matrix.get(x, y) ? 0xEE854E : 0xFFFFFFFF);
                } else {
                    // 绿色
                    image.setRGB(x, y, matrix.get(x, y) ? 0x2DBD8D : 0xFFFFFFFF);
                }
            }
        }
        return image;
    }

	public static void main(String[] args) {
		System.out.println(genQrCodeBase64Png("101",100,100));
		System.out.println(genQrCodeBase64PngWithWord("101",100,100,"sd",100));
	}

}
