# qr_printer.py - Brother QL-710W QR 라벨 인쇄
# person-lookup-web-local/print_label.py에서 핵심 기능만 추출

from PIL import Image, ImageDraw, ImageFont
import io
import logging
import qrcode

# 프린터 설정
PRINTER_IP = "192.168.0.121"
PRINTER_MODEL = "QL-710W"
LABEL_TYPE = "29"  # 29mm 연속 출력 용지

# Windows 폰트 경로
FONT_PATH = "C:/Windows/Fonts/malgunbd.ttf"

logging.basicConfig(level=logging.INFO)


def create_drug_qr_label(drug_name, barcode, sale_price, drug_code=None, pharmacy_name='청춘약국'):
    """
    약품 QR 라벨 이미지 생성

    Parameters:
        drug_name (str): 약품명
        barcode (str): 바코드 (QR 코드로 변환)
        sale_price (float): 판매가격
        drug_code (str, optional): 약품 코드 (바코드가 없을 때 대체)
        pharmacy_name (str, optional): 약국 이름

    Returns:
        PIL.Image: 생성된 라벨 이미지
    """
    label_width = 306
    label_height = 380
    image = Image.new("1", (label_width, label_height), "white")
    draw = ImageDraw.Draw(image)

    # 폰트 설정
    try:
        drug_name_font = ImageFont.truetype(FONT_PATH, 32)
        price_font = ImageFont.truetype(FONT_PATH, 36)
        label_font = ImageFont.truetype(FONT_PATH, 24)
    except IOError:
        drug_name_font = ImageFont.load_default()
        price_font = ImageFont.load_default()
        label_font = ImageFont.load_default()
        logging.warning("폰트 로드 실패. 기본 폰트 사용.")

    # 바코드가 없으면 약품 코드 사용
    qr_data = barcode if barcode else (drug_code if drug_code else "NO_BARCODE")

    # QR 코드 생성
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=4,
        border=1,
    )
    qr.add_data(qr_data)
    qr.make(fit=True)
    qr_img = qr.make_image(fill_color="black", back_color="white")

    # QR 코드 크기 조정 및 배치
    qr_size = 130
    qr_img = qr_img.resize((qr_size, qr_size), Image.LANCZOS)
    qr_x = (label_width - qr_size) // 2
    qr_y = 15

    if qr_img.mode != '1':
        qr_img = qr_img.convert('1')
    image.paste(qr_img, (qr_x, qr_y))

    # 약품명 (QR 코드 아래)
    y_position = qr_y + qr_size + 10

    def draw_wrapped_text(draw, text, y, font, max_width):
        """텍스트를 여러 줄로 표시"""
        chars = list(text)
        lines = []
        current_line = ""

        for char in chars:
            test_line = current_line + char
            bbox = draw.textbbox((0, 0), test_line, font=font)
            w = bbox[2] - bbox[0]

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

        if current_line:
            lines.append(current_line)

        lines = lines[:2]  # 최대 2줄

        for line in lines:
            bbox = draw.textbbox((0, 0), line, font=font)
            w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
            draw.text(((label_width - w) / 2, y), line, font=font, fill="black")
            y += h + 5

        return y

    y_position = draw_wrapped_text(draw, drug_name, y_position, drug_name_font, label_width - 40)
    y_position += 8

    # 가격
    if sale_price and sale_price > 0:
        price_text = f"₩{int(sale_price):,}"
    else:
        price_text = "가격 미정"

    bbox = draw.textbbox((0, 0), price_text, font=price_font)
    w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
    draw.text(((label_width - w) / 2, y_position), price_text, font=price_font, fill="black")
    y_position += h + 15

    # 구분선
    line_margin = 30
    draw.line([(line_margin, y_position), (label_width - line_margin, y_position)], fill="black", width=2)
    y_position += 20

    # 약국 이름
    signature_text = " ".join(pharmacy_name)
    bbox = draw.textbbox((0, 0), signature_text, font=label_font)
    w_sig, h_sig = bbox[2] - bbox[0], bbox[3] - bbox[1]

    padding = 10
    box_x = (label_width - w_sig) / 2 - padding
    box_y = y_position
    box_x2 = box_x + w_sig + 2 * padding
    box_y2 = box_y + h_sig + 2 * padding
    draw.rectangle([(box_x, box_y), (box_x2, box_y2)], outline="black", width=2)
    draw.text(((label_width - w_sig) / 2, box_y + padding), signature_text, font=label_font, fill="black")

    # 절취선 테두리
    draw_scissor_border(draw, label_width, label_height)

    return image


def draw_scissor_border(draw, width, height, edge_size=10, steps=20):
    """절취선 테두리"""
    # 상단
    top_points = []
    step_x = width / (steps * 2)
    for i in range(steps * 2 + 1):
        x = i * step_x
        y = 0 if i % 2 == 0 else edge_size
        top_points.append((int(x), int(y)))
    draw.line(top_points, fill="black", width=2)

    # 하단
    bottom_points = []
    for i in range(steps * 2 + 1):
        x = i * step_x
        y = height if i % 2 == 0 else height - edge_size
        bottom_points.append((int(x), int(y)))
    draw.line(bottom_points, fill="black", width=2)

    # 좌측
    left_points = []
    step_y = height / (steps * 2)
    for i in range(steps * 2 + 1):
        y = i * step_y
        x = 0 if i % 2 == 0 else edge_size
        left_points.append((int(x), int(y)))
    draw.line(left_points, fill="black", width=2)

    # 우측
    right_points = []
    for i in range(steps * 2 + 1):
        y = i * step_y
        x = width if i % 2 == 0 else width - edge_size
        right_points.append((int(x), int(y)))
    draw.line(right_points, fill="black", width=2)


def print_drug_qr_label(drug_name, barcode, sale_price, drug_code=None, pharmacy_name='청춘약국'):
    """
    약품 QR 라벨 인쇄 실행

    Parameters:
        drug_name (str): 약품명
        barcode (str): 바코드
        sale_price (float): 판매가격
        drug_code (str, optional): 약품 코드
        pharmacy_name (str, optional): 약국 이름

    Returns:
        dict: 성공/실패 결과
    """
    try:
        from brother_ql.raster import BrotherQLRaster
        from brother_ql.conversion import convert
        from brother_ql.backends.helpers import send

        label_image = create_drug_qr_label(drug_name, barcode, sale_price, drug_code, pharmacy_name)

        # 이미지를 메모리 스트림으로 변환
        image_stream = io.BytesIO()
        label_image.save(image_stream, format="PNG")
        image_stream.seek(0)

        # Brother QL 프린터로 전송
        qlr = BrotherQLRaster(PRINTER_MODEL)
        instructions = convert(
            qlr=qlr,
            images=[Image.open(image_stream)],
            label=LABEL_TYPE,
            rotate="0",
            threshold=70.0,
            dither=False,
            compress=False,
            lq=True,
            red=False
        )
        send(instructions, printer_identifier=f"tcp://{PRINTER_IP}:9100")

        logging.info(f"QR 라벨 인쇄 성공: {drug_name}, 바코드={barcode}")
        return {"success": True, "message": f"{drug_name} QR 라벨 인쇄 완료"}

    except ImportError as e:
        logging.error(f"brother_ql 라이브러리 없음: {e}")
        return {"success": False, "error": "brother_ql 라이브러리가 설치되지 않았습니다"}
    except Exception as e:
        logging.error(f"QR 라벨 인쇄 실패: {e}")
        return {"success": False, "error": str(e)}


def preview_qr_label(drug_name, barcode, sale_price, drug_code=None, pharmacy_name='청춘약국'):
    """
    QR 라벨 미리보기 (base64 이미지 반환)
    """
    import base64
    
    label_image = create_drug_qr_label(drug_name, barcode, sale_price, drug_code, pharmacy_name)
    
    # PNG로 변환
    image_stream = io.BytesIO()
    # 1-bit 이미지를 RGB로 변환하여 더 깔끔하게
    rgb_image = label_image.convert('RGB')
    rgb_image.save(image_stream, format="PNG")
    image_stream.seek(0)
    
    base64_image = base64.b64encode(image_stream.read()).decode('utf-8')
    return f"data:image/png;base64,{base64_image}"


if __name__ == "__main__":
    # 테스트
    result = print_drug_qr_label(
        drug_name="벤포파워Z",
        barcode="8806418067510",
        sale_price=3000,
        pharmacy_name="청춘약국"
    )
    print(result)
