package com.mortals.xhx.module.print.service.PrintComponent;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.mortals.framework.util.DataUtil;
import com.mortals.xhx.common.code.PrintAlignStyleEnum;
import com.mortals.xhx.common.code.PrintContentTypeEnum;
import com.mortals.xhx.common.code.PrintFontStyleEnum;
import com.mortals.xhx.common.utils.QrCodeUtil;
import com.mortals.xhx.module.print.model.PrintContent;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 文本小票打印
 *
 * @author:
 * @date: 2022/12/27 16:15
 */
@Slf4j
public class TicketPrinter implements Printable {

    // 每行的空闲高度
    static final int lineHeight = 3;
    // 页边距宽度
    @Setter
    @Getter
    private Integer marginWidth;

    @Setter
    @Getter
    private Integer marginTop;

    @Setter
    @Getter
    private List<PrintContent> printContentList;

    public int getActualHeight(PageFormat pageFormat) {
        int xIndex = (int) pageFormat.getImageableX();
        int yIndex = (int) pageFormat.getImageableY() + marginTop;
        double imageableWidth = pageFormat.getPaper().getImageableWidth();
        int charPerLine = (int) imageableWidth - marginWidth;

        BufferedImage dimg = new BufferedImage((int) imageableWidth, (int) pageFormat.getPaper().getImageableWidth(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics2D = dimg.createGraphics();

        for (int i = 0; i < printContentList.size(); i++) {
            //设置每行打印属性
            PrintContent printContent = printContentList.get(i);
            Map<TextAttribute, Object> hm = new HashMap<>();
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_UNDERLINE.getValue())) {
                hm.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); // 定义是否有下划线
            }
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_BOLD.getValue())) {
                hm.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); // 定义加粗
            }
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_ITALIC.getValue())) {
                hm.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); // 是否斜体
            }
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_REGULAR.getValue())) {
                hm.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); // 正常
            }
            hm.put(TextAttribute.SIZE, Integer.parseInt(printContent.getFontsize())); // 定义字号
            hm.put(TextAttribute.FAMILY, printContent.getFontname()); // 定义字体名
            Font font = new Font(hm); // 生成字号为12，字体为宋体，字形带有下划线的字体
            graphics2D.setFont(font);
            //设置打印颜色为黑色
            graphics2D.setColor(Color.black);
            // 背景色白色
            graphics2D.setBackground(new Color(255, 255, 255));
            //判断行内容是否为文本
            if (PrintContentTypeEnum.PRINT_TEXT.getValue().equals(printContent.getPrinttype())) {
                //文本输出
                yIndex = drawString(graphics2D, printContent.getContent(), printContent.getAlign(), xIndex, yIndex, charPerLine, lineHeight);
            } else if (PrintContentTypeEnum.PRINT_SEPARATE.getValue().equals(printContent.getPrinttype())) {
                //分隔符
                //测算分隔符宽度
                FontMetrics fontMetrics = graphics2D.getFontMetrics();
                int sepWidth = fontMetrics.stringWidth(printContent.getContent());
                int count = charPerLine / sepWidth;
                String repeatStr = StrUtil.repeat(printContent.getContent(), count);
                yIndex = drawString(graphics2D, repeatStr, printContent.getAlign(), xIndex, yIndex, charPerLine, lineHeight);
            } else if (PrintContentTypeEnum.PRINT_BARCODE.getValue().equals(printContent.getPrinttype())) {
                //条形码
                BufferedImage bufferedImage = QrCodeUtil.getBarCode(printContent.getContent());
                bufferedImage= QrCodeUtil.insertWords(bufferedImage,printContent.getContent());
                if(bufferedImage==null){
                    continue;
                }
                yIndex = drawBarCode(graphics2D, bufferedImage, printContent.getAlign(), xIndex, yIndex, charPerLine);
            } else if (printContent.getPrinttype().equals(PrintContentTypeEnum.PRINT_QRCODE.getValue())) {
                //二维码
                int imgWidth = printContent.getImgwidth() == null ? 100 : DataUtil.converStr2Int(printContent.getImgwidth(), 100);
                BufferedImage bufferedImage = QrCodeUtil.generateQrCode(printContent.getContent(), imgWidth);
                yIndex = drawQrCode(graphics2D, bufferedImage, printContent.getAlign(), xIndex, yIndex, charPerLine);
            } else if (printContent.getPrinttype().equals(PrintContentTypeEnum.PRINT_IMG.getValue())) {
                //图片
                byte[] bytes = HttpUtil.downloadBytes(printContent.getContent());
                if (bytes.length > 0) {
                    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                    try {
                        BufferedImage image = ImageIO.read(in);
                        BufferedImage resizeBufferdImage = resize(image, DataUtil.converStr2Int(printContent.getImgwidth(), 0));
                        yIndex = drawImage(graphics2D, resizeBufferdImage, printContent.getAlign(), xIndex, yIndex, charPerLine);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            } else {
                //默认文本
                yIndex = drawString(graphics2D, printContent.getContent(), printContent.getAlign(), xIndex, yIndex, charPerLine, lineHeight);
            }
        }
        graphics2D.dispose();
        return yIndex;
    }

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
        // 当打印页号大于需要打印的总页数时，打印工作结束
        // 绘制打印内容
        Graphics2D graphics2D = (Graphics2D) graphics;
        if (pageIndex > 0) {
            return NO_SUCH_PAGE;
        }

        log.info("字体高度："+graphics2D.getFontMetrics().getHeight());
        // 获取设定的纸张高度
        // int height = (int) pageFormat.getPaper().getHeight();
        // 计算每张图片有多少行文字
        //int lineCount = height / lineHeight;
        // 获取设置的纸张宽度
        double imageableWidth = pageFormat.getPaper().getImageableWidth();
        // 计算每行最大字符数
        //int charPerLine = (int) imageableWidth / stringWidth;
        int charPerLine = (int) imageableWidth - marginWidth;
        // 获取打印的起点坐标
        int xIndex = (int) pageFormat.getImageableX();
        int yIndex = (int) pageFormat.getImageableY() + marginTop;

        for (int i = 0; i < printContentList.size(); i++) {
            //设置每行打印属性
            PrintContent printContent = printContentList.get(i);
            Map<TextAttribute, Object> hm = new HashMap<>();
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_UNDERLINE.getValue())) {
                hm.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); // 定义是否有下划线
            }
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_BOLD.getValue())) {
                hm.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); // 定义加粗
            }
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_ITALIC.getValue())) {
                hm.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); // 是否斜体
            }
            if (printContent.getFontstyle().equals(PrintFontStyleEnum.PRINT_REGULAR.getValue())) {
                hm.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); // 正常
            }
            hm.put(TextAttribute.SIZE, Integer.parseInt(printContent.getFontsize())); // 定义字号
            hm.put(TextAttribute.FAMILY, printContent.getFontname()); // 定义字体名
            Font font = new Font(hm); // 生成字号为12，字体为宋体，字形带有下划线的字体
            graphics2D.setFont(font);
            //设置打印颜色为黑色
            graphics2D.setColor(Color.black);
            // 背景色白色
            graphics2D.setBackground(new Color(255, 255, 255));
            //判断行内容是否为文本
            if (PrintContentTypeEnum.PRINT_TEXT.getValue().equals(printContent.getPrinttype())) {
                //文本输出
                yIndex = drawString(graphics2D, printContent.getContent(), printContent.getAlign(), xIndex, yIndex, charPerLine, lineHeight);
            } else if (PrintContentTypeEnum.PRINT_SEPARATE.getValue().equals(printContent.getPrinttype())) {
                //分隔符
                //测算分隔符宽度
                FontMetrics fontMetrics = graphics2D.getFontMetrics();
                int sepWidth = fontMetrics.stringWidth(printContent.getContent());
                int count = charPerLine / sepWidth;
                String repeatStr = StrUtil.repeat(printContent.getContent(), count);
                yIndex = drawString(graphics2D, repeatStr, printContent.getAlign(), xIndex, yIndex, charPerLine, lineHeight);
            } else if (PrintContentTypeEnum.PRINT_BARCODE.getValue().equals(printContent.getPrinttype())) {
                //条形码
                BufferedImage bufferedImage = QrCodeUtil.getBarCode(printContent.getContent());
                bufferedImage= QrCodeUtil.insertWords(bufferedImage,printContent.getContent());
                if(bufferedImage==null){
                    continue;
                }
                yIndex = drawBarCode(graphics2D, bufferedImage, printContent.getAlign(), xIndex, yIndex, charPerLine);
            } else if (printContent.getPrinttype().equals(PrintContentTypeEnum.PRINT_QRCODE.getValue())) {
                //二维码
                int imgWidth = printContent.getImgwidth() == null ? 100 : DataUtil.converStr2Int(printContent.getImgwidth(), 100);
                BufferedImage bufferedImage = QrCodeUtil.generateQrCode(printContent.getContent(), imgWidth);
                yIndex = drawQrCode(graphics2D, bufferedImage, printContent.getAlign(), xIndex, yIndex, charPerLine);
            } else if (printContent.getPrinttype().equals(PrintContentTypeEnum.PRINT_IMG.getValue())) {
                //图片
                byte[] bytes = HttpUtil.downloadBytes(printContent.getContent());
                if (bytes.length > 0) {
                    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                    try {
                        BufferedImage image = ImageIO.read(in);
                        BufferedImage resizeBufferdImage = resize(image, DataUtil.converStr2Int(printContent.getImgwidth(), 0));
                        yIndex = drawImage(graphics2D, resizeBufferdImage, printContent.getAlign(), xIndex, yIndex, charPerLine);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            } else {
                //默认文本
                yIndex = drawString(graphics2D, printContent.getContent(), printContent.getAlign(), xIndex, yIndex, charPerLine, lineHeight);
            }
        }
        graphics2D.dispose();
        return PAGE_EXISTS;
    }

    private static int drawString(Graphics2D graphics2D, String text, String align, int x, int y, int lineWidth, int lineHeight) {
        //计算文本宽度
        FontMetrics fontMetrics = graphics2D.getFontMetrics();
        int strWidth = fontMetrics.stringWidth(text);
        //测量是否需要换行
        StringBuilder sb = new StringBuilder();
        int textLength = text.length();
        int totalWidth = fontMetrics.stringWidth(text); //文本的总长度，用于判断是否超出了范围
        if (totalWidth > lineWidth) {
            int nowWidth = 0; //目前一行写的长度
            //遍历当前文本行
            for (int i = 0; i < textLength; i++) {
                sb.append(text.charAt(i));
                int oneWordWidth = fontMetrics.charWidth(text.charAt(i)); //获取单个字符的长度
                int tempWidth = oneWordWidth + nowWidth; //判断目前的一行加上这个字符的长度是否超出了总长度
                if (tempWidth > lineWidth) {
                    //如果超出了一行的总长度，则要换成下一行 并画当前行
                    //int writeY = y + alreadyWriteLine * (textHeight + heightSpace);
                    y = drawAlignString(graphics2D, sb.toString(), align, x, y, lineWidth, lineHeight, tempWidth);
                    sb = new StringBuilder();
                    nowWidth = 0;
                } else {
                    nowWidth = tempWidth;
                }
            }
            if (sb.toString().length() > 0) {
                y = drawAlignString(graphics2D, sb.toString(), align, x, y, lineWidth, lineHeight, fontMetrics.stringWidth(sb.toString()));
            }
        } else {
            //  没有超过限制，直接画
            y = drawAlignString(graphics2D, text, align, x, y, lineWidth, lineHeight, strWidth);
        }
        return y;
    }

    private static int drawAlignString(Graphics2D graphics2D, String text, String align, int x, int y, int lineWidth, int lineHeight, int strWidth) {
        //int heightSpace=0;
        int fontHeight = graphics2D.getFontMetrics().getHeight();
        lineHeight = fontHeight + lineHeight;
        //布局方式
        if (PrintAlignStyleEnum.PRINT_CENTER.getValue().equals(align)) {
            //居中
            graphics2D.drawString(text, (lineWidth - strWidth) / 2, y);
            return y + lineHeight;
        } else if (PrintAlignStyleEnum.PRINT_RIGHT.getValue().equals(align)) {
            //居右
            graphics2D.drawString(text, lineWidth - strWidth, y);
            return y + lineHeight;
        } else {
            //默认靠左
            graphics2D.drawString(text, x, y);
            return y + lineHeight;
        }
    }


    public static BufferedImage resize(BufferedImage img, int newW) {
        //根据比例
        BigDecimal radio = new BigDecimal(img.getWidth()).divide(new BigDecimal(img.getHeight()), 2, BigDecimal.ROUND_CEILING);
        int newH = new BigDecimal(newW).divide(radio, 2, BigDecimal.ROUND_CEILING).intValue();
        Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
        BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = dimg.createGraphics();
        g2d.drawImage(tmp, 0, 0, null);
        g2d.dispose();
        return dimg;
    }

    private static int drawBarCode(Graphics2D graphics2D, BufferedImage bufferedImage, String align, int x, int y, int lineWidth) {
        //布局方式
        if (PrintAlignStyleEnum.PRINT_CENTER.getValue().equals(align)) {
            //居中
            graphics2D.drawImage(bufferedImage, null, (lineWidth - bufferedImage.getWidth()) / 2, y);
            return y + bufferedImage.getHeight() + lineHeight;
        } else if (PrintAlignStyleEnum.PRINT_RIGHT.getValue().equals(align)) {
            //居右
            graphics2D.drawImage(bufferedImage, null, lineWidth - bufferedImage.getWidth(), y);
            return y + bufferedImage.getHeight() + lineHeight;
        } else {
            //默认靠左
            graphics2D.drawImage(bufferedImage, null, x, y);
            return y + bufferedImage.getHeight() + lineHeight;
        }
    }

    private static int drawQrCode(Graphics2D graphics2D, BufferedImage bufferedImage, String align, int x, int y, int lineWidth) {
        //布局方式
        if (PrintAlignStyleEnum.PRINT_CENTER.getValue().equals(align)) {
            //居中
            graphics2D.drawImage(bufferedImage, null, (lineWidth - bufferedImage.getWidth()) / 2, y);
            return y + bufferedImage.getHeight() + lineHeight;
        } else if (PrintAlignStyleEnum.PRINT_RIGHT.getValue().equals(align)) {
            //居右
            graphics2D.drawImage(bufferedImage, null, lineWidth - bufferedImage.getWidth(), y);
            return y + bufferedImage.getHeight() + lineHeight;
        } else {
            //默认靠左
            graphics2D.drawImage(bufferedImage, null, x, y);
            return y + bufferedImage.getHeight() + lineHeight;
        }
    }

    private static int drawImage(Graphics2D graphics2D, BufferedImage bufferedImage, String align, int x, int y, int lineWidth) {
        //布局方式
        if (PrintAlignStyleEnum.PRINT_CENTER.getValue().equals(align)) {
            //居中
            graphics2D.drawImage(bufferedImage, null, (lineWidth - bufferedImage.getWidth()) / 2, y);
            return y + bufferedImage.getHeight() + lineHeight;
        } else if (PrintAlignStyleEnum.PRINT_RIGHT.getValue().equals(align)) {
            //居右
            graphics2D.drawImage(bufferedImage, null, lineWidth - bufferedImage.getWidth(), y);
            return y + bufferedImage.getHeight() + lineHeight;
        } else {
            //默认靠左
            graphics2D.drawImage(bufferedImage, null, x, y);
            return y + bufferedImage.getHeight() + lineHeight;
        }
    }

    public static void main(String[] args) {


        int w = 1080;
        int h = 1620;

        BigDecimal divide = new BigDecimal(w).divide(new BigDecimal(h), 2, BigDecimal.ROUND_CEILING);

        System.out.println(divide.doubleValue());


       /* int charPerLine = 10;
        int lineCount = 10;
        List<PrintContent> printContentList = new ArrayList<>();

        PrintContent printContent = new PrintContent();
        printContent.setContent("写了一个打印机遇到打印纸张输出的问题打印纸张有或者当设置纸张的时候需要横向打印");

        printContentList.add(printContent);


        List<PrintContent> newList = new ArrayList<>();
        // 计算处理后得到信息需要打印的页数及换行
        for (int j = 0; j < printContentList.size(); j++) {
            PrintContent content = printContentList.get(j);
            if (content.getContent().length() > charPerLine) {
                //换行
                String substring = content.getContent().substring(0, charPerLine);
                PrintContent temp = new PrintContent();
                BeanUtils.copyProperties(content, temp);
                temp.setContent(substring);
                newList.add(temp);
                content.setContent(content.getContent().substring(charPerLine));
                //裁剪后添加到过的内容到后一位
                printContentList.add(j + 1, content);
                //修改当前裁剪的内容
                printContentList.set(j, temp);
            } else {
                newList.add(content);
            }
        }


        // 计算处理后得到信息需要打印的页数
        int a = newList.size();
        int pageNum = a % lineCount == 0 ? (a / lineCount) : (a / lineCount) + 1;
        System.out.println(JSON.toJSONString(newList));
        System.out.println(pageNum);*/


    }

}
