package com.czg.service.order.print;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.HandoverRecord;
import com.czg.order.entity.OrderDetail;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 打印机具体打印方法接口，提供打印元数据获取，具体打印机实现对应方法即可
 *
 * @author Administrator
 */
public interface PrinterImpl {
    @Data
    @Accessors(chain = true)
    class PrintSignLabel {
        private String[] center;
        private String[] centerBold;
        private String[] bold;
        private String br;
        private String[] s;
        private String[] f;
        private String[] l;
        private String[] qr;
        private String cut;
        private String out;
        private String rs;

        public String getOut(int num) {
            if (out != null) {
                return StrUtil.format("<{}:{}>", out, num);
            }
            return "";
        }


        /**
         * @param num 最小1，最大127，不设置则为默认
         */
        public String getRs(int num) {
            if (StrUtil.isNotBlank(rs)) {
                return StrUtil.format("<{}:{}>", rs, num);
            }
            return "";
        }
    }


    /**
     * 发送打印请求
     *
     * @param address       打印地址
     * @param metaPrintData 打印元数据
     * @param voiceData     语音信息
     * @param printNum      打印联数
     * @param <R>           返回数据类型
     * @return 打印结果
     */
    <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);

    /**
     * 获取当前打印机标签信息
     *
     * @return 标签信息
     */
    PrintSignLabel getSignLabelInfo();


    /**
     * 获取对齐后的小票明细行数据
     * 例如：58mm 机器一行打印16个汉字/32个字母；80mm机器打印24个汉字/48个字母。
     *
     * @param title 品名
     * @param price 单价
     * @param num   数量
     * @param total 小计
     * @param b1    品名占用字节数
     * @param b2    单价占用字节数
     * @param b3    数量占用字节数
     * @param b4    小计占用字节数
     * @return 格式化后的行数据（带<S>和<BR>标签）
     */
    default String getRow(String title, String price, String num, String total,
                          int b1, int b2, int b3, int b4) {
        PrintSignLabel signLabelInfo = getSignLabelInfo();
        price = addSpace(price, b2);
        num = addSpace(num, b3);
        total = addSpace(total, b4);
        String otherStr = "%s%s%s".formatted(price, num, total);

        int titleByteLen = StrUtil.bytes(title, CharsetUtil.CHARSET_GBK).length;
        StringBuilder sb = new StringBuilder();

        if (titleByteLen <= b1) {
            // 品名可以在一行显示，直接补足空格
            title = titleAddSpace(title, b1);
            sb.append(getFormatLabel(title + otherStr, signLabelInfo.s));
//            sb.append(startSplitSign).append(title).append(otherStr).append(endSplitSign);
        } else {
            // 品名超出一行，进行拆分
            List<String> lines = isEn(title)
                    // 英文按 b1 个字符拆分
                    ? getStrList(title, b1)
                    // 中文按 b1/2 个字符拆分
                    : getStrList(title, b1 / 2);

            // 第一行拼接其它字段
            String firstLine = titleAddSpace(lines.getFirst(), b1);
//            sb.append(startSplitSign).append(firstLine).append(otherStr).append(endSplitSign).append("<BR>");

            sb.append(getFormatLabel(firstLine + otherStr, signLabelInfo.s));

            sb.append(signLabelInfo.br);

            // 剩余的行单独换行输出
            for (int i = 1; i < lines.size(); i++) {
                if (i+1 != lines.size()) {
//                    sb.append(signLabelInfo.getRs(1));
                    sb.append(getFormatLabel(titleAddSpace(lines.get(i), b1), signLabelInfo.s));
                    sb.append(signLabelInfo.br);
                }else {
                    sb.append(getFormatLabel(titleAddSpace(lines.get(i), b1), signLabelInfo.s));
                }
//                sb.append(startSplitSign).append(lines.get(i)).append(endSplitSign).append("BR>");
            }
        }
        sb.append(signLabelInfo.br);
        return sb.toString();
    }

    default String getFormatLabel(String text, String[]... labels) {
        StringBuilder str = new StringBuilder();
        for (String[] label : labels) {
            str.append(label[0]);
        }

        str.append(text);
        for (int i = labels.length - 1; i >= 0; i--) {
            str.append(labels[i][1]);
        }
        return str.toString();
    }

    default String buildHandoverData(HandoverRecordDTO handoverRecord) {
        PrintSignLabel signLabelInfo = getSignLabelInfo();
        StringBuilder builder = new StringBuilder()
                .append(getFormatLabel(handoverRecord.getShopName(), signLabelInfo.center, signLabelInfo.f)).append(signLabelInfo.br)
                .append(getFormatLabel("交班小票", signLabelInfo.l,signLabelInfo.center)).append(signLabelInfo.br)
                .append("交班时间: ").append(DateUtil.format(handoverRecord.getHandoverTime(), "yyyy-MM-dd HH:mm:ss")).append(signLabelInfo.br)
                .append("收银员: ").append(handoverRecord.getStaffName()).append(signLabelInfo.br)
                .append("当班总收入: ").append(handoverRecord.getHandAmount()).append(signLabelInfo.br)
                .append("现金收入: ").append(handoverRecord.getCashAmount()).append(signLabelInfo.br)
                .append("微信收入: ").append(handoverRecord.getWechatAmount()).append(signLabelInfo.br)
                .append("支付宝收入: ").append(handoverRecord.getAlipayAmount()).append(signLabelInfo.br)
                .append("会员支付: ").append(handoverRecord.getVipPay()).append(signLabelInfo.br)
                .append("会员充值: ").append(handoverRecord.getVipRecharge()).append(signLabelInfo.br)
                .append(signLabelInfo.br)
                .append(signLabelInfo.br)
                .append("分类数据").append(signLabelInfo.br).append(signLabelInfo.br)
                .append(getFormatLabel("名称                数量  总计  ", signLabelInfo.s))
                .append(signLabelInfo.br)
                .append(signLabelInfo.br);

        if (StrUtil.isNotBlank(handoverRecord.getCategoryData())) {
            JSONArray.parseArray(handoverRecord.getCategoryData()).forEach(item -> {
                JSONObject info = (JSONObject) item;
                String categoryName = info.getString("categoryName");
                Integer quantity = info.getInteger("quantity");
                BigDecimal amount = info.getBigDecimal("amount");
                builder.append(getRow(categoryName, "", quantity.toString(), amount.toPlainString(), 20, 0, 6, 6)).append(signLabelInfo.br);
            });
        }
        builder.append(signLabelInfo.br);
        builder.append(signLabelInfo.br);
        builder.append("商品数据")
                .append(signLabelInfo.br)
                .append(signLabelInfo.br);
        builder.append(getFormatLabel("名称                      总计  ", signLabelInfo.s))
                .append(signLabelInfo.br)
                .append(signLabelInfo.br);

        if (StrUtil.isNotBlank(handoverRecord.getProductData())) {
            JSONArray.parseArray(handoverRecord.getProductData()).forEach(item -> {
                JSONObject info = (JSONObject) item;
                String productName = info.getString("productName");
                String skuName = info.getString("skuName");
                if (StrUtil.isNotBlank(skuName)) {
                    productName = productName + "-" + skuName;
                }
                BigDecimal num = info.getBigDecimal("num");
//                builder.append(signLabelInfo.getRs(5));
                builder.append(getRow(productName, "", "", num.toPlainString(), 25, 0, 1, 6)).append(signLabelInfo.br);
            });
        }

        builder
                .append(signLabelInfo.br)
                .append(signLabelInfo.br)
                .append("快捷收款金额: ").append(handoverRecord.getQuickInAmount()).append(signLabelInfo.br)
                .append("退款金额: ").append(handoverRecord.getRefundAmount()).append(signLabelInfo.br)
                .append("总收入: ").append(handoverRecord.getHandAmount()).append(signLabelInfo.br)
                .append("挂账金额: ").append(handoverRecord.getCreditAmount()).append(signLabelInfo.br)
                .append("总订单数: ").append(handoverRecord.getOrderCount()).append(signLabelInfo.br)
                .append("打印时间: ").append(DateUtil.date()).append(signLabelInfo.br)
                .append(signLabelInfo.getOut(180))
                .append(signLabelInfo.cut)
        ;
        return builder.toString();
    }

    /**
     * 构建订单打印元数据
     *
     * @param printInfoDTO 打印信息
     * @param detailList   订单详情
     * @return 订单打印元数据
     */
    default String buildOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
        PrintSignLabel signLabelInfo = getSignLabelInfo();
        StringBuilder data = new StringBuilder();
        data.append(getFormatLabel(printInfoDTO.getShopName(), signLabelInfo.center, signLabelInfo.f)).append(signLabelInfo.br);
//        data.append(StrUtil.format("<C><F>{}</F></C><BR>", printInfoDTO.getShopName()));
//        data.append("<BR>");
//        data.append("<OUT:30>");
        data.append(getFormatLabel(StrUtil.format("{}  #{}", printInfoDTO.getPrintTitle(), printInfoDTO.getCount()), signLabelInfo.l,  signLabelInfo.center))
                .append(signLabelInfo.br);
        data.append(getFormatLabel(StrUtil.format("桌号: {}", printInfoDTO.getPickupNum()), signLabelInfo.l, signLabelInfo.center))
                .append(signLabelInfo.br);

//        data.append(StrUtil.format("<C><BOLD>{}【{}】</BOLD></C><BR>", printInfoDTO.getPrintTitle(), printInfoDTO.getPickupNum()));
        //if (Objects.nonNull(printInfoDTO.getOutNumber())) {
        //    data.append(StrUtil.format("<CB><BOLD>{}</BOLD></CB>",printInfoDTO.getOutNumber()));
        //}
//        data.append("<OUT:30>");
//        data.append("<BR>");
        data.append(getFormatLabel(StrUtil.format("订单号：{}", printInfoDTO.getOrderNo()), signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append(StrUtil.format("<S>订单号：{}</S><BR>", printInfoDTO.getOrderNo()));
        data.append(getFormatLabel(StrUtil.format("交易时间：{}", printInfoDTO.getTradeDate()), signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append(StrUtil.format("<S>交易时间：{}</S><BR>", printInfoDTO.getTradeDate()));
        data.append(getFormatLabel(StrUtil.format("收银员：{}", printInfoDTO.getOperator()), signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append(StrUtil.format("<S>收银员：{}</S><BR>", printInfoDTO.getOperator()));
        data.append(signLabelInfo.br);
        data.append(signLabelInfo.br);
//        data.append("<OUT:15>");
//        data.append("<BR>");
        // 18个空格 12
        data.append(getFormatLabel("品名                 数量 小计  ", signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append("<S>品名                 数量 小计</S><BR>");
        data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append("<S>--------------------------------</S><BR>");
        for (OrderDetail detail : detailList) {
            String number = detail.getNum().stripTrailingZeros().toPlainString();
            String row = getRow(detail.getProductName(), "", StrUtil.format("{}{}", number, detail.getReturnNum().compareTo(BigDecimal.ZERO) > 0 ?
                            "(退" + detail.getReturnNum().stripTrailingZeros().toPlainString() + ")" : ""),
                    toPlainStr(detail.getUnitPrice().stripTrailingZeros().toPlainString()), 21, 0, 5, 6);
            data.append(row);
            if (StrUtil.isNotBlank(detail.getSkuName())) {
                data.append(getFormatLabel(StrUtil.format("规格：{}", detail.getSkuName()), signLabelInfo.s))
                        .append(signLabelInfo.br);
//                data.append("<S>规格:").append(detail.getSkuName()).append("</S><BR>");
            }
            String proGroupInfo = detail.getProGroupInfo();
            if (StrUtil.isBlank(proGroupInfo)) {
                continue;
            }
            if (!JSONUtil.isTypeJSONArray(proGroupInfo)) {
                continue;
            }
            JSONArray subItems = com.alibaba.fastjson2.JSONArray.parseArray(proGroupInfo);
            for (Object subItem : subItems) {
                JSONObject jsonObject = (JSONObject) subItem;
                jsonObject.getJSONArray("goods").forEach(item -> {
                    String proName = ((JSONObject) item).getString("proName");
                    String qty = ((JSONObject) item).getString("number");
                    String subRow = getRow(" - " + proName, "", qty, "0.00", 21, 0, 5, 6);
                    data.append(subRow);
                });
            }
        }
        if(StrUtil.isNotBlank(printInfoDTO.getSeatAmount())){
            String row = getRow("餐位费", "", StrUtil.format("{}{}", printInfoDTO.getSeatNum(),""),
                    toPlainStr(printInfoDTO.getSeatAmount()), 21, 0, 5, 6);
            data.append(row);
        }
        if(StrUtil.isNotBlank(printInfoDTO.getPackFee())){
            String row = getRow("打包费", "", "",
                    toPlainStr(printInfoDTO.getPackFee()), 21, 0, 5, 6);
            data.append(row);
        }
        if (ObjectUtil.isNotNull(printInfoDTO.getDiscountAmount())) {
            data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
                    .append(signLabelInfo.br);
//            data.append("<S>--------------------------------</S><BR>");
            data.append(getFormatLabel(StrUtil.format("原价：{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
                    .append(signLabelInfo.br);
//            data.append(StrUtil.format("<S>原价：{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
            data.append(getFormatLabel(StrUtil.format("优惠：-{}", toPlainStr(printInfoDTO.getDiscountAmount())), signLabelInfo.s))
                    .append(signLabelInfo.br);
//            data.append(StrUtil.format("<S>折扣：-{}</S><BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
        }
        data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append("<S>--------------------------------</S><BR>");
        String t = "￥" + printInfoDTO.getPayAmount();
        if (printInfoDTO.isReturn()) {
            data.append(getFormatLabel(StrUtil.format("应退：{}", t), signLabelInfo.f))
                    .append(signLabelInfo.br);
//            data.append("<F>应退").append(t).append("</F><BR>");
        } else {
            data.append(getFormatLabel(StrUtil.format("应收：{}", t), signLabelInfo.f))
                    .append(signLabelInfo.br);
//            data.append(StrUtil.format("<F>应收：{}</F><BR>", t));
        }
        data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
                .append(signLabelInfo.br);
//        data.append("<S>--------------------------------</S><BR>");
        if (ObjectUtil.isNotEmpty(printInfoDTO.getPayType()) && ObjectUtil.isNotNull(printInfoDTO.getPayType()) && "deposit".equals(printInfoDTO.getPayType())) {
            data.append(getFormatLabel(StrUtil.format("储值：{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
                    .append(signLabelInfo.br);
//            data.append(StrUtil.format("<S>储值：{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
            data.append(getFormatLabel(StrUtil.format("积分：{}", printInfoDTO.getIntegral()), signLabelInfo.s))
                    .append(signLabelInfo.br);
//            data.append(StrUtil.format("<S>积分：{}</S><BR>", printInfoDTO.getIntegral()));
            data.append(getFormatLabel(StrUtil.format("余额：{}", toPlainStr(printInfoDTO.getBalance())), signLabelInfo.s))
                    .append(signLabelInfo.br);
//        data.append(StrUtil.format("<S>余额：{}</S><BR>", toPlainStr(printInfoDTO.getBalance())));
            data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
                    .append(signLabelInfo.br);
        }

//        data.append("<S>--------------------------------</S><BR>");
        if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
            data.append(getFormatLabel(StrUtil.format("备注：{}", printInfoDTO.getRemark()), signLabelInfo.l, signLabelInfo.bold))
                    .append(signLabelInfo.br);
//            data.append(StrUtil.format("<L><BOLD>备注：{}</BOLD></L><BR>", printInfoDTO.getRemark()));
        }
        if (Objects.nonNull(printInfoDTO.getOutNumber())) {
            data.append(getFormatLabel(printInfoDTO.getOutNumber(), signLabelInfo.center, signLabelInfo.qr))
                    .append(signLabelInfo.br);
//            data.append("<QR>".concat(printInfoDTO.getOutNumber()).concat("</QR><BR>"));
        }
        data.append(getFormatLabel(StrUtil.format("打印时间：{}", DateUtil.date().toString()), signLabelInfo.s))
                .append(signLabelInfo.br)
                .append(signLabelInfo.br);
//        data.append("<S>打印时间:").append(DateUtil.date().toDateStr()).append("</S><BR>");
//        data.append("<OUT:180>");
        data.append(signLabelInfo.getOut(180));
        data.append(signLabelInfo.cut);
//        data.append("<PCUT>");
        return data.toString();
    }

    /**
     * 构建菜品单打印数据
     *
     * @param pickupNumber 取餐号
     * @param date         时间
     * @param productName  商品名
     * @param skuName      规格名称
     * @param number       数量
     * @param remark       备注
     * @param proGroupInfo 套餐信息
     * @return 元数据
     */
    default String buildDishPrintData(boolean isReturn, String pickupNumber, String date, String productName, String skuName, BigDecimal number, String remark, String proGroupInfo) {
        PrintSignLabel signLabelInfo = getSignLabelInfo();
        StringBuilder builder = new StringBuilder();
        if (isReturn) {
            builder.append(getFormatLabel(StrUtil.format("{}【退】", pickupNumber), signLabelInfo.centerBold))
                    .append(signLabelInfo.br)
                    .append(signLabelInfo.br);
//            builder.append("<C><B>").append(pickupNumber).append("【退】</B></C><BR><BR>");
        } else {
            builder.append(getFormatLabel(pickupNumber, signLabelInfo.centerBold))
                    .append(signLabelInfo.br)
                    .append(signLabelInfo.br);
//            builder.append("<C><B>").append(pickupNumber).append("</B></C><BR><BR>");
        }
        builder.append(getFormatLabel(StrUtil.format("时间: {}", date), signLabelInfo.l, signLabelInfo.center))
                .append(signLabelInfo.br)
                .append(signLabelInfo.br);
//        builder.append("<S><L>时间: ").append(date).append(" </L></S><BR><BR><BR>");
        if (productName.length() > 4) {
            builder.append(getFormatLabel(StrUtil.format("{} x {}", productName, number.stripTrailingZeros().toPlainString()), signLabelInfo.l, signLabelInfo.f, signLabelInfo.center))
                    .append(signLabelInfo.br);
//            builder.append("<CS:32>").append(productName).append(" x ").append(number).append("</CS><BR>");
            if (StrUtil.isNotBlank(skuName)) {
                builder.append(getFormatLabel("(" + skuName + ")", signLabelInfo.l, signLabelInfo.f, signLabelInfo.center)).append(signLabelInfo.br);
//                builder.append("<CS:32>").append(skuName).append(" </CS><BR>");
            }
        } else {
            builder.append(getFormatLabel(StrUtil.format("{} x {}", productName, number.stripTrailingZeros().toPlainString()), signLabelInfo.l, signLabelInfo.f, signLabelInfo.center))
                    .append(signLabelInfo.br);
//            builder.append("<B>").append(productName).append(" x ").append(number).append("</B><BR>");
            if (StrUtil.isNotBlank(skuName)) {
                builder.append(getFormatLabel("(" + skuName + ")", signLabelInfo.l, signLabelInfo.f, signLabelInfo.center))
                        .append(signLabelInfo.br);
//                builder.append("<B>").append(skuName).append(" </B><BR>");
            }
        }
        if (StrUtil.isNotBlank(remark)) {
            builder.append(signLabelInfo.br);
            builder.append(getFormatLabel(StrUtil.format("备注：{}", remark), signLabelInfo.s, signLabelInfo.l))
                    .append(signLabelInfo.br);
//            builder.append("<S><L>备注: ").append(note).append(" </L></S><BR>");
        }
        if (!StrUtil.isBlank(proGroupInfo) && JSONUtil.isTypeJSONArray(proGroupInfo)) {
            JSONArray subItems = JSONArray.parseArray(proGroupInfo);
            for (Object subItem : subItems) {
                JSONObject jsonObject = (JSONObject) subItem;
                jsonObject.getJSONArray("goods").forEach(item -> {
                    String proName = ((JSONObject) item).getString("proName");
                    String qty = ((JSONObject) item).getString("number");
                    builder.append(StrUtil.format("({}) x {}", proName, qty))
                            .append(signLabelInfo.br);
                });

//                builder.append("<CS:32>(").append(i + 1).append(")").append(proName).append(" x ").append(qty).append("</CS><BR>");
            }
        }
        builder.append(signLabelInfo.br)
                .append(signLabelInfo.getOut(150))
                .append(signLabelInfo.cut);
//        builder.append("<OUT:150>");
//        builder.append("<PCUT>");
        return builder.toString();
    }

    /**
     * 构建叫号元数据
     *
     * @param shopName  店铺名称
     * @param tableName 表名
     * @param callNum   号码
     * @param preNum    前面还有几桌
     * @param codeUrl   二维码地址
     * @param shopNote  店铺备注
     * @param takeTime  取号时间
     * @return 元数据
     */
    default String buildCallTicketData(String shopName, String tableName, String callNum, String preNum, String codeUrl, String shopNote, LocalDateTime takeTime) {
        PrintSignLabel signLabelInfo = getSignLabelInfo();
        //        sb.append("<C><B>").append(shopName).append("</B></C><BR><BR>")
//                .append("------------------------<BR>")
//                .append(StrUtil.format(StrUtil.format("<C><B>{} {}</B></C><BR>", tableName, callNum)))
//                .append(StrUtil.format("<C>前面有{}桌</C><BR>", preNum))
//                .append(StrUtil.format("<C><QR>{}</QR></C><BR>", codeUrl))
//                .append("<C><B>怕过号扫一扫<B></C><BR>")
//                .append("------------------------<BR>")
//                .append(StrUtil.format("<S>{}</S><BR>", shopNote))
//                .append("------------------------<BR>").append("<S>取号时间:").append(DateUtil.format(takeTime, "yyyy-MM-dd HH:mm:ss"))
//                .append("</S><BR>").append("<S>打印时间:").append(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")).append("</S><BR>")
//                .append("<OUT:180>").append("<PCUT>");
        return getFormatLabel(shopName, signLabelInfo.center, signLabelInfo.bold) +
                signLabelInfo.br +
                signLabelInfo.br +
                getFormatLabel(StrUtil.format("{} {}", tableName, callNum), signLabelInfo.center, signLabelInfo.bold) +
                signLabelInfo.br +
                getFormatLabel(StrUtil.format("前面有{}桌", preNum), signLabelInfo.center) +
                signLabelInfo.br +
                getFormatLabel("怕过号扫一扫", signLabelInfo.center, signLabelInfo.bold) +
                signLabelInfo.br +
                getFormatLabel(codeUrl, signLabelInfo.center, signLabelInfo.qr) +
                signLabelInfo.br +
                "--------------------------------" + signLabelInfo.br +
                getFormatLabel(shopNote, signLabelInfo.s) +
                signLabelInfo.br +
                "--------------------------------" + signLabelInfo.br +
                getFormatLabel(StrUtil.format("取号时间：{}", DateUtil.format(takeTime, "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s) +
                signLabelInfo.br +
                getFormatLabel(StrUtil.format("打印时间：{}", DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s) +
                signLabelInfo.br +
                signLabelInfo.cut;
    }

    /**
     * 按字符数补足空格（英文、数字时使用）
     *
     * @param str  对应字符串
     * @param size 总长度
     * @return 填充之后的字符串
     */
    default String addSpace(String str, int size) {
        int len = str.length();
        if (len < size) {
            str = str + " ".repeat(size - len);
        }
        return str;
    }

    /**
     * 按固定长度拆分字符串（按字符拆分）
     *
     * @param inputString 字符串
     * @param length      每个长度
     * @return 分割后的集合
     */
    default List<String> getStrList(String inputString, int length) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < inputString.length(); i += length) {
            list.add(StrUtil.sub(inputString, i, Math.min(i + length, inputString.length())));
        }
        return list;
    }


    /**
     * 判断字符串是否全为英文（GBK编码下，每个字符均为 1 字节）
     *
     * @param str 字符
     * @return 是否英文
     */
    default boolean isEn(String str) {
        return StrUtil.bytes(str, CharsetUtil.CHARSET_GBK).length == str.length();
    }

    /**
     * 根据 GBK 字节数补空格（用于中文排版）
     *
     * @param str 字符串
     * @param b1  总长度
     * @return 添加间距的字符串
     */
    default String titleAddSpace(String str, int b1) {
        int k = 0;
        try {
            k = str.getBytes("GBK").length;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        str = str + " ".repeat(Math.max(0, b1 - k));
        return str;
    }

    public static void main(String[] args) {
        System.out.println("水煮肉片".length());
        System.out.println(StrUtil.repeat(' ', 8));
        System.out.println(StrUtil.fillAfter("水煮肉片", ' ', 21));
    }

    /**
     * 获取填充字符串, 并且换行
     *
     * @param length 长度
     * @param string 字符串
     * @return 填充字符串
     */
    default String getStringByEnter(String string, int length) {
        PrintSignLabel signLabelInfo = getSignLabelInfo();
        StringBuilder result = new StringBuilder();
        while (!string.isEmpty()) {
            int pos = 0, byteCount = 0;
            for (int i = 0; i < string.length(); i++) {
                int charByteLen = StrUtil.bytes(string.substring(i, i + 1), CharsetUtil.CHARSET_GBK).length;
                if (byteCount + charByteLen > length) {
                    break;
                }
                byteCount += charByteLen;
                pos = i + 1;
            }
            result.append(signLabelInfo.s[0]).append(string, 0, pos).append(signLabelInfo.s[1]);
            string = string.substring(pos);
            if (!string.isEmpty()) {
                result.append("<BR>");
            }
        }
        return result.toString();
    }

    /**
     * 获取规格化的字符串
     *
     * @param str 字符串
     * @return 返回规格化字符串
     */
    default String toPlainStr(String str) {
        if (StrUtil.isBlank(str)) {
            return "0";
        }
        return NumberUtil.roundDown(new BigDecimal(str), 2).toPlainString();
    }
}
