import socket
import base64
import os
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont

# 引入二维码生成库
try:
    import qrcode
except ImportError:
    print("❌ 警告: 未安装 qrcode 库，无法生成二维码。请执行: pip install qrcode[pil]")


class LabelPrintService:
    PRINTER_IP = "192.168.9.205"
    PRINTER_PORT = 9100

    # ================= 1. 尺寸与分辨率配置 (300 DPI) =================
    DOTS_PER_MM = 12  # 300 DPI
    LABEL_WIDTH_MM = 40
    LABEL_HEIGHT_MM = 30

    # 画布像素: 40mm -> 480px, 30mm -> 360px
    LABEL_WIDTH = int(LABEL_WIDTH_MM * DOTS_PER_MM)
    LABEL_HEIGHT = int(LABEL_HEIGHT_MM * DOTS_PER_MM)

    # ================= 2. 布局配置 =================
    MARGIN_LEFT = int(2 * DOTS_PER_MM)  # 左边距 2mm
    MARGIN_RIGHT = int(1 * DOTS_PER_MM)  # 右边距 1mm
    TOP_MARGIN = int(5 * DOTS_PER_MM)  # 顶部边距 2mm

    # 二维码尺寸 15mm * 15mm
    QR_SIZE_MM = 15
    QR_SIZE_PX = int(QR_SIZE_MM * DOTS_PER_MM)  # 180px

    # 左右分栏的间距
    GAP_COLUMNS = int(2 * DOTS_PER_MM)  # 2mm 间距

    @staticmethod
    def _get_font(size):
        """获取字体 (优先使用黑体/微软雅黑)"""
        font_names = ["simhei.ttf", "msyh.ttf", "SimHei.ttf", "arial.ttf", "NotoSansCJK-Regular.ttc"]
        base_dirs = [os.getcwd(), os.path.dirname(__file__), "/usr/share/fonts", "C:\\Windows\\Fonts"]

        for d in base_dirs:
            for name in font_names:
                path = os.path.join(d, name)
                if os.path.exists(path):
                    try:
                        return ImageFont.truetype(path, size)
                    except:
                        continue
        return ImageFont.load_default()

    @staticmethod
    def _generate_qr_image(content, size_px):
        """生成指定像素大小的二维码"""
        try:
            if not content: content = "000000"

            # 创建二维码对象
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_M,
                box_size=10,
                border=0,
            )
            qr.add_data(content)
            qr.make(fit=True)

            img = qr.make_image(fill_color="black", back_color="white")

            # [重要] 必须转为 RGB 模式
            img = img.convert('RGB')

            # 调整为指定像素大小
            return img.resize((size_px, size_px), Image.Resampling.LANCZOS)
        except Exception as e:
            print(f"二维码生成失败: {e}")
            return Image.new('RGB', (size_px, size_px), color='gray')

    @staticmethod
    def draw_text_wrap(draw, text, x, y, font, max_width, line_spacing=0, stroke_width=1):
        """
        [核心功能] 自动换行绘制文本
        """
        if not text:
            return y

        lines = []
        current_line = ""

        # 计算折行
        for char in text:
            test_line = current_line + char
            width = font.getlength(test_line)

            if width <= max_width:
                current_line = test_line
            else:
                if current_line: lines.append(current_line)
                current_line = char

        if current_line:
            lines.append(current_line)

        # 绘制
        current_y = y
        font_height = font.size

        for line in lines:
            if current_y + font_height > LabelPrintService.LABEL_HEIGHT:
                break

            draw.text(
                (x, current_y),
                line,
                font=font,
                fill='black',
                stroke_width=stroke_width,  # 支持动态调整粗细
                stroke_fill='black'
            )
            current_y += font_height + line_spacing

        return current_y

    @staticmethod
    def _create_image_object(data):
        """
        [绘图层] 生成标签图片
        新布局逻辑：
        ---------------------------------------
        | [QR Code] (15mm) |  名: XXXXXX      |
        |                  |  规: XXXXXX      |
        | SKU: XXXXX(大/粗)|  属: XXXXXX      |
        | 库: XXXXX (中/粗)|  SN: XXXXXX      |
        ---------------------------------------
        """
        # 1. 创建画布
        img = Image.new('RGB', (LabelPrintService.LABEL_WIDTH, LabelPrintService.LABEL_HEIGHT), color='white')
        d = ImageDraw.Draw(img)

        # 2. 字体配置 (字号再次加大)
        # [修改] 通用字体加大到 28
        font_text = LabelPrintService._get_font(28)
        # [修改] SKU字体加大到 34 (特大)
        font_sku = LabelPrintService._get_font(34)

        # 3. 数据准备
        sku_code = str(data.get('sku') or data.get('serial_number') or '000000')

        name = str(data.get('material_name', '') or '-')
        spec = str(data.get('spec_model', '') or '-')
        loc = str(data.get('warehouse_loc', '') or '-')

        cat = str(data.get('category', '') or '')
        typ = str(data.get('material_type', '') or '')
        attr = f"{cat}/{typ}" if (cat or typ) else "-"

        # 底部编号逻辑
        bottom_val = ""
        bottom_label = "NO"
        if data.get('print_no'):
            bottom_val = str(data.get('print_no'))
            l_type = data.get('print_label', '')
            bottom_label = 'SN' if l_type == '序' else 'BN' if l_type == '批' else 'NO'
        elif data.get('serial_number'):
            bottom_label = "SN"
            bottom_val = str(data.get('serial_number'))
        elif data.get('batch_number'):
            bottom_label = "BN"
            bottom_val = str(data.get('batch_number'))
        else:
            bottom_val = sku_code

        bottom_text_full = f"{bottom_label}:{bottom_val}"

        # ==================== 绘制区域划分 ====================

        # --- A. 左侧区域 (二维码 + SKU + 库位) ---
        qr_x = LabelPrintService.MARGIN_LEFT
        qr_y = LabelPrintService.TOP_MARGIN

        # 1. 绘制二维码
        qr_img = LabelPrintService._generate_qr_image(sku_code, LabelPrintService.QR_SIZE_PX)
        img.paste(qr_img, (qr_x, qr_y))

        # 计算中心点，用于 SKU 和 库位 居中
        qr_center_x = qr_x + (LabelPrintService.QR_SIZE_PX // 2)

        # 2. 绘制 SKU (特大 + 特粗)
        # 位于二维码下方，留 6px 间距
        current_left_y = qr_y + LabelPrintService.QR_SIZE_PX + 6

        sku_w = font_sku.getlength(sku_code)
        sku_x = int(qr_center_x - (sku_w // 2))
        if sku_x < 2: sku_x = 2  # 边界保护

        d.text(
            (sku_x, current_left_y),
            sku_code,
            font=font_sku,
            fill='black',
            stroke_width=2,  # [修改] SKU 增加到 2px 描边，更粗
            stroke_fill='black'
        )

        # 3. 绘制 库位 (放在 SKU 下方)
        # 位于 SKU 下方，留 6px 间距
        current_left_y += 34 + 6  # 34是字号大致高度

        loc_text = f"库:{loc}"
        loc_w = font_text.getlength(loc_text)
        loc_x = int(qr_center_x - (loc_w // 2))
        if loc_x < 2: loc_x = 2

        d.text(
            (loc_x, current_left_y),
            loc_text,
            font=font_text,
            fill='black',
            stroke_width=1,  # 普通加粗
            stroke_fill='black'
        )

        # --- B. 右侧区域 (名称、规格、属性、编号) ---

        # 右侧起始 X
        right_start_x = LabelPrintService.MARGIN_LEFT + LabelPrintService.QR_SIZE_PX + LabelPrintService.GAP_COLUMNS
        # 右侧最大宽度
        right_max_width = LabelPrintService.LABEL_WIDTH - right_start_x - LabelPrintService.MARGIN_RIGHT

        current_right_y = LabelPrintService.TOP_MARGIN

        # [修改] 增大行间距 line_spacing=8
        LINE_SPACING = 8

        # 1. 名称
        current_right_y = LabelPrintService.draw_text_wrap(
            d, f"名:{name}", right_start_x, current_right_y, font_text, right_max_width, line_spacing=LINE_SPACING
        )
        current_right_y += LINE_SPACING

        # 2. 规格
        current_right_y = LabelPrintService.draw_text_wrap(
            d, f"规:{spec}", right_start_x, current_right_y, font_text, right_max_width, line_spacing=LINE_SPACING
        )
        current_right_y += LINE_SPACING

        # 3. 属性
        current_right_y = LabelPrintService.draw_text_wrap(
            d, f"属:{attr}", right_start_x, current_right_y, font_text, right_max_width, line_spacing=LINE_SPACING
        )
        current_right_y += LINE_SPACING

        # 4. 序列号/批号
        LabelPrintService.draw_text_wrap(
            d, bottom_text_full, right_start_x, current_right_y, font_text, right_max_width, line_spacing=LINE_SPACING
        )

        return img

    @staticmethod
    def generate_preview_image(data):
        """生成 Base64 预览图"""
        img = LabelPrintService._create_image_object(data)
        output_buffer = BytesIO()
        img.save(output_buffer, format='JPEG', quality=95)
        base64_str = base64.b64encode(output_buffer.getvalue()).decode('utf-8')
        return f"data:image/jpeg;base64,{base64_str}"

    @staticmethod
    def send_to_printer(data):
        ip = LabelPrintService.PRINTER_IP
        port = LabelPrintService.PRINTER_PORT

        try:
            # 1. 获取 RGB 图像
            img_rgb = LabelPrintService._create_image_object(data)

            # 2. 转换为灰度
            img_gray = img_rgb.convert('L')

            # 3. 二值化处理
            img_bw = img_gray.point(lambda x: 0 if x < 128 else 255, '1')

            # 4. 生成打印指令
            bitmap_data = img_bw.tobytes()
            width_bytes = (img_bw.width + 7) // 8
            height_dots = img_bw.height

            # TSPL 协议头
            header = (
                f"SIZE {LabelPrintService.LABEL_WIDTH_MM} mm, {LabelPrintService.LABEL_HEIGHT_MM} mm\r\n"
                "GAP 2 mm, 0 mm\r\n"
                "CLS\r\n"
                "DIRECTION 1\r\n"
                "REFERENCE 0, 0\r\n"
            ).encode('gbk')

            # 位图指令
            bitmap_cmd = f"BITMAP 0,0,{width_bytes},{height_dots},0,".encode('gbk')
            footer = b"\r\nPRINT 1,1\r\n"

            # 5. 发送 socket
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(5)
            s.connect((ip, port))
            s.sendall(header + bitmap_cmd + bitmap_data + footer)
            s.close()
            return True
        except Exception as e:
            print(f"❌ 打印异常: {e}")
            raise Exception(f"打印机连接失败: {str(e)}")


if __name__ == "__main__":
    pass