package com.iotechn.unimall.data.util;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
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 lombok.Getter;
import lombok.SneakyThrows;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.font.FontDesignMetrics;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Properties;

/**
 * @Author:chengchangjiang
 * @Description: 二维码Util类
 * @Date:Created in 9:38 2021-09-03
 */
@Component
public class QRCodeUtil implements InitializingBean {

    @Value("${oss.aliyun.oss.basekUrl}")
    private String baseUrl;
    @Value("${oss.aliyun.oss.bucket}")
    private String bucket;
    @Autowired
    private OSSClient ossClient;
    @Value("${oss.aliyun.oss.endpoint}")
    private String endpoint;

    private String host;
    @Override
    public void afterPropertiesSet() throws Exception {
        host = "http://" + bucket + "." + endpoint;
    }

    /***
     * 生成二维码图片并上传OSS
     * @param text 二维码内容
     * @param width 宽度
     * @param height 高度
     * @param type 类型
     * @param name 图片名字
     * @return
     */
    public  String generateQRCodeImage(String text, int width, int height,String type,String name){
        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            Hashtable<EncodeHintType, Object> hints = new Hashtable();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = qrCodeWriter.encode(type+"="+text, BarcodeFormat.QR_CODE, width, height,hints);

            File file = new File( new String(("templates" + File.separator + name+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
            if(!file.exists()){
                boolean flag = file.mkdirs();
            }
            Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());

            MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);

            FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());

            MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
            String result = upload(multipartFile,name);
            file.delete();
            return result;
        }
        catch (Exception e){
            System.out.println("二维码异常："+e.toString());
            return "error";
        }
    }
    /**
     * 后台通过服务器间接传文件
     * @param file
     * @return
     * @throws IOException
     */
    public  String upload(MultipartFile file, String sendCarNo) throws IOException {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(file.getSize());
        objectMetadata.setContentType(file.getContentType());
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, "QRCode/" +sendCarNo+".png", file.getInputStream(), objectMetadata);
        ossClient.putObject(putObjectRequest);
        return baseUrl + "QRCode/" + sendCarNo+".png";
    }

    private static final int QRCODE_SIZE = 320; // 二维码尺寸，宽度和高度均是320
    private static final String FORMAT_TYPE = "PNG"; // 二维码图片类型


//    //1、生成带logo和底部文字得二维码
//    @SneakyThrows
//    @GetMapping("/getQrCode1")
//    public void getQrCode1(HttpServletResponse response) {
//        ServletOutputStream os = response.getOutputStream();
//        BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test", "底部文字");
//        response.setContentType("image/png");
//        ImageIO.write(bufferedImage,"png",os);
//    }
//    //2、生成不带logo和底部文字得二维码
//    @SneakyThrows
//    @GetMapping("/getQrCode2")
//    public void getQrCode2(HttpServletResponse response) {
//        ServletOutputStream os = response.getOutputStream();
//        BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test", false);
//        response.setContentType("image/png");
//        ImageIO.write(bufferedImage,"png",os);
//    }
//    //3、生成默认带logo不带底部文字得二维码
//    @SneakyThrows
//    @GetMapping("/getQrCode3")
//    public void getQrCode3(HttpServletResponse response) {
//        ServletOutputStream os = response.getOutputStream();
//        BufferedImage bufferedImage = QRCodeUtil.generateQRCodeImage("test");
//        response.setContentType("image/png");
//        ImageIO.write(bufferedImage,"png",os);
//    }
//    //3、生成不带logo带底部文字得二维码
//    @SneakyThrows
//    public  getQrCode3(HttpServletResponse response) {
//        ServletOutputStream os = response.getOutputStream();
//        BufferedImage bufferedImage = QRCodeUtil.getQRCodeImage("test",false,
//                "底部文字");
//        response.setContentType("image/png");
//        ImageIO.write(bufferedImage,"png",os);
//    }


    /**
     * 获取二维码图片
     *
     * @param dataStr    二维码内容
     * @param needLogo   是否需要添加logo
     * @param bottomText 底部文字       为空则不显示
     * @return
     */
    @SneakyThrows
    public String getQRCodeImage(String dataStr, boolean needLogo, String bottomText ,String name) {
        if (dataStr == null) {
            throw new RuntimeException("未包含任何信息");
        }
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");    //定义内容字符集的编码
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);        //定义纠错等级
        hints.put(EncodeHintType.MARGIN, 1);
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(dataStr, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);

        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        int tempHeight = height;
        if (StringUtils.hasText(bottomText)) {
            tempHeight = tempHeight + 12;
        }
        BufferedImage image = new BufferedImage(width, tempHeight, 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);
            }
        }
        // 判断是否添加logo
        if (needLogo) {
            insertLogoImage(image);
        }
        // 判断是否添加底部文字
        if (StringUtils.hasText(bottomText)) {
            addFontImage(image, bottomText);
        }

        File file = new File( new String(("templates" + File.separator + name+".png").getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
        if(!file.exists()){
            boolean flag = file.mkdirs();
        }
        Path path = FileSystems.getDefault().getPath(file.getAbsoluteFile().getPath());

//        ByteArrayOutputStream out = new ByteArrayOutputStream();
//        ImageIO.write(image,"png",path);
//        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);

        //创建一个ByteArrayOutputStream
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        //把BufferedImage写入ByteArrayOutputStream
        ImageIO.write(image, "png", os);
        //ByteArrayOutputStream转成InputStream
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        //InputStream转成MultipartFile
        MultipartFile multipartFile =new MockMultipartFile("file", "file.jpg", "text/plain", input);

//        FileInputStream fileInputStream = new FileInputStream(file.getAbsoluteFile());
//        MultipartFile multipartFile = new MockMultipartFile( ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
        String result = upload(multipartFile,name);
        file.delete();
        return result;
    }

    /**
     * 插入logo图片
     *
     * @param source 二维码图片
     * @throws Exception
     */
    private static void insertLogoImage(BufferedImage source) throws Exception {
        // 默认logo放于resource/static/image目录下
        ClassPathResource classPathResource = new ClassPathResource("static/image/logo.png");
        InputStream inputStream = classPathResource.getInputStream();
        if (inputStream == null || inputStream.available() == 0) {
            return;
        }
        Image src = ImageIO.read(inputStream);
        int width = 30;
        int height = 30;

        Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = tag.getGraphics();
        g.drawImage(image, 0, 0, null); // 绘制缩小后的图
        g.dispose();
        src = image;

        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    private static void addFontImage(BufferedImage source, String declareText) {
        //生成image
        int defineWidth = QRCODE_SIZE;
        int defineHeight = 20;
        BufferedImage textImage = new BufferedImage(defineWidth, defineHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) textImage.getGraphics();
        //开启文字抗锯齿
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,   RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2.setBackground(Color.WHITE);
        g2.clearRect(0, 0, defineWidth, defineHeight);
        g2.setPaint(Color.BLACK);
        FontRenderContext context = g2.getFontRenderContext();
        String font_cn = getChineseFont();
        //部署linux需要注意 linux无此字体会显示方块
        Font font = new Font("宋体", Font.BOLD, 18);

        g2.setFont(font);
        LineMetrics lineMetrics = font.getLineMetrics(declareText, context);
        FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);
        float offset = (defineWidth - fontMetrics.stringWidth(declareText)) / 2;
        float y = (defineHeight + lineMetrics.getAscent() - lineMetrics.getDescent() - lineMetrics.getLeading()) / 2;
        g2.drawString(declareText, (int) offset, (int) y);

        Graphics2D graph = source.createGraphics();
        //开启文字抗锯齿
        graph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,   RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        //添加image
        int width = textImage.getWidth(null);
        int height = textImage.getHeight(null);

        Image src = textImage;
        graph.drawImage(src, 0, QRCODE_SIZE - 8, width, height, Color.WHITE, null);
        graph.dispose();
    }
    /**
     * 获取中文字体位置
     *
     * @return
     * @author xxj 2017年4月28日
     */
    private static String getChineseFont() {

        //宋体（对应css中的 属性 font-family: SimSun; /*宋体*/）
        String font1 = "templates" + File.separator + "msyh.ttc";
//        String font1 = "templates" + File.separator + "simsun.ttf";
        //判断系统类型，加载字体文件
        Properties prop = System.getProperties();
        String osName = prop.getProperty("os.name").toLowerCase();
        System.out.println(osName);
        if (osName.indexOf("linux") > -1) {
            font1 = "/usr/share/fonts/chinese/simsun.ttc";
        }
        else{
            font1 = "宋体";
        }
        return font1;
    }
}
