# print_label.py

from PIL import Image, ImageDraw, ImageFont
import io
import logging
from brother_ql.raster import BrotherQLRaster
from brother_ql.conversion import convert
from brother_ql.backends.helpers import send
import datetime  # 날짜 처리를 위해 추가
import pytz
import re
import qrcode
import json

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

# 로깅 설정
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(message)s')

# KOR 시간대 설정
KOR_TZ = pytz.timezone('Asia/Seoul')


def format_total_amount(dosage, frequency, duration):
    """
    1회 복용량, 복용 횟수, 총 복용 일수를 기반으로 총량을 계산하고,
    1/4 단위로 반올림하거나 그대로 반환합니다.
    
    Parameters:
        dosage (float): 1회 복용량 (소수 넷째 자리까지 포함 가능)
        frequency (int): 1일 복용 횟수
        duration (int): 복용 일수
    
    Returns:
        str: 포맷팅된 총량 문자열
    """
    if frequency > 0 and duration > 0:
        # 1일 복용량 = 1회 복용량 * 1일 복용 횟수
        daily_dosage = dosage * frequency
        # 총량 = 1일 복용량 * 총 복용 일수
        total_amount = daily_dosage * duration

        # 1회 복용량이 소수 넷째 자리까지 있는 경우 1/4 단위로 반올림
        if round(dosage, 4) != round(dosage, 3):  # 소수 넷째 자리 여부 확인
            total_amount = round(total_amount * 4) / 4

        # 정수인 경우 소수점 없이 표시, 소수가 있는 경우 둘째 자리까지 표시
        return str(int(total_amount)) if total_amount.is_integer() else f"{total_amount:.2f}".rstrip('0').rstrip('.')
    return "0"  # 복용 횟수나 복용 일수가 0인 경우


def format_dosage(dosage):
    """
    1회 복용량을 포맷팅합니다.
    
    Parameters:
        dosage (float): 1회 복용량
    
    Returns:
        str: 포맷팅된 복용량 문자열
    """
    if dosage.is_integer():
        return str(int(dosage))
    else:
        # 최대 4자리 소수까지 표시, 불필요한 0 제거
        return f"{dosage:.4f}".rstrip('0').rstrip('.')


def format_converted_total(dosage, frequency, duration, conversion_factor):
    """
    총량을 계산하고 환산계수를 곱한 변환된 총량을 포맷팅합니다.

    Parameters:
        dosage (float): 1회 복용량 (소수 넷째 자리까지 포함 가능)
        frequency (int): 1일 복용 횟수
        duration (int): 복용 일수
        conversion_factor (float): 환산계수

    Returns:
        str: 변환된 총량을 포함한 포맷팅된 문자열
    """
    if frequency > 0 and duration > 0 and conversion_factor is not None:
        total_amount = dosage * frequency * duration
        if round(dosage, 4) != round(dosage, 3):
            total_amount = round(total_amount * 4) / 4
        converted_total = total_amount * conversion_factor
        if converted_total.is_integer():
            return str(int(converted_total))
        else:
            return f"{converted_total:.2f}".rstrip('0').rstrip('.')
    return None


def draw_scissor_border(draw, width, height, edge_size=5, steps=230):
    """
    라벨 이미지의 테두리에 톱니 모양의 절취선을 그립니다.

    Parameters:
        draw (ImageDraw.Draw): 이미지에 그리기 위한 Draw 객체
        width (int): 라벨 너비
        height (int): 라벨 높이
        edge_size (int): 톱니 크기
        steps (int): 톱니 반복 횟수
    """
    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 split_med_name(med_name):
    """
    약품 이름을 표시용 이름과 시그니처 정보로 분리합니다.

    Parameters:
        med_name (str): 약품 이름

    Returns:
        tuple: (표시용 약품 이름, 시그니처 정보, 분리 여부)
    """
    units = ['mg', 'g', 'ml', '%']
    pattern = r'(\d+(?:\.\d+)?(?:/\d+(?:\.\d+)?)*)\s*(' + '|'.join(units) + r')(?:/(' + '|'.join(units) + r'))?$'
    korean_only = re.fullmatch(r'[가-힣]+', med_name) is not None
    korean_and_num_eng = re.fullmatch(r'[가-힣a-zA-Z0-9/\.]+', med_name) is not None and not korean_only
    med_name_display = med_name
    signature_info = "청 춘 약 국"
    split_occurred = False
    if korean_only:
        if len(med_name) >= 10:
            match = re.search(pattern, med_name)
            if match and match.start() >= 10:
                med_name_display = med_name[:match.start()].strip()
                signature_info = match.group(1) + match.group(2) + (f"/{match.group(3)}" if match.group(3) else "")
                split_occurred = True
            else:
                med_name_display = med_name[:10]
        # else 그대로 사용
    elif korean_and_num_eng:
        if len(med_name) >= 13:
            match = re.search(pattern, med_name)
            if match:
                med_name_display = med_name[:match.start()].strip()
                signature_info = match.group(1) + match.group(2) + (f"/{match.group(3)}" if match.group(3) else "")
                split_occurred = True
            else:
                med_name_display = med_name[:12]
    return med_name_display, signature_info, split_occurred


def should_left_align(med_name_display):
    """
    약품 이름의 길이와 구성을 기반으로 좌측 정렬 여부를 결정합니다.

    Parameters:
        med_name_display (str): 분리된 약품 이름 표시 부분

    Returns:
        bool: 좌측 정렬 여부
    """
    korean_only = re.fullmatch(r'[가-힣]+', med_name_display) is not None
    korean_and_num_eng = re.fullmatch(r'[가-힣a-zA-Z0-9/\.]+', med_name_display) is not None and not korean_only

    if korean_only and len(med_name_display) >= 10:         # 10글자부터 좌측정렬 (한글단독)
        return True
    if korean_and_num_eng and len(med_name_display) >= 13:   # 13글자부터 좌측정렬 (한글+숫자+영문)
        return True
    return False


def create_label_image(patient_name, med_name, add_info, frequency, dosage, duration,
                       formulation_type, main_ingredient_code, dosage_form, administration_route,
                       label_name, unit, conversion_factor=None, storage_condition="실온보관",
                       custom_dosage_instruction=""):
    """
    라벨 이미지를 생성합니다.

    Parameters:
        patient_name (str): 환자 이름
        med_name (str): 약품 이름
        add_info (str): 약품 효능 정보
        frequency (int): 복용 횟수
        dosage (float): 복용량
        duration (int): 복용 일수
        formulation_type (str): 제형 타입
        main_ingredient_code (str): 주성분 코드 
        dosage_form (str): 복용 형태
        administration_route (str): 투여 경로
        label_name (str): 라벨 명칭
        unit (str): 복용 단위
        conversion_factor (float, optional): 환산계수
        storage_condition (str, optional): 보관 조건
        custom_dosage_instruction (str, optional): 커스텀 용법 텍스트

    Returns:
        PIL.Image: 생성된 라벨 이미지
    """
    # 라벨 이미지 설정
    label_width = 306  # 29mm 용지에 해당하는 너비 픽셀 수 (300 dpi 기준)
    label_height = 380  # 라벨 높이를 380으로 확장하여 추가 정보 포함  (Glabel 기준 380 적당)
    image = Image.new("1", (label_width, label_height), "white")
    draw = ImageDraw.Draw(image)

    # 폰트 설정 (여기서 폰트를 규정하고 요소에서 불러서 사용)
    font_path = "/root/project/react_cclabel/backend/fonts/malgunbd.ttf"
    try:
        patient_name_font = ImageFont.truetype(font_path, 44)
        drug_name_font = ImageFont.truetype(font_path, 32)
        info_font = ImageFont.truetype(font_path, 30)
        signature_font = ImageFont.truetype(font_path, 32)
        print_date_font = ImageFont.truetype(font_path, 20)  # 조제일 폰트 추가
        additional_info_font = ImageFont.truetype(font_path, 27)  # 추가 정보 폰트
        storage_condition_font = ImageFont.truetype(font_path, 27)  # 보관 조건 폰트
    except IOError:
        patient_name_font = ImageFont.load_default()
        drug_name_font = ImageFont.load_default()
        info_font = ImageFont.load_default()
        signature_font = ImageFont.load_default()
        print_date_font = ImageFont.load_default()  # 조제일 폰트 기본값 사용
        additional_info_font = ImageFont.load_default()  # 추가 정보 폰트 기본값 사용
        storage_condition_font = ImageFont.load_default()  # 보관 조건 폰트 기본값 사용
        logging.warning("폰트 로드 실패. 기본 폰트 사용.")

    # 중앙 정렬된 텍스트 출력 함수
    def draw_centered_text(draw, text, y, font, max_width=None):
        if not text:
            return y
        lines = []
        if max_width:
            words = re.findall(r'\S+', text)
            current_line = ""
            for word in words:
                test_line = f"{current_line} {word}".strip()
                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 = word
            if current_line:
                lines.append(current_line)
        else:
            lines = [text]
        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

    def draw_left_aligned_text(draw, text, y, font, max_width=None):
        if not text:
            return y
        lines = []
        if max_width:
            words = re.findall(r'\S+', text)
            current_line = ""
            for word in words:
                test_line = f"{current_line} {word}".strip()
                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 = word
            if current_line:
                lines.append(current_line)
        else:
            lines = [text]
        for line in lines:
            bbox = draw.textbbox((0, 0), line, font=font)
            w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
            draw.text((10, y), line, font=font, fill="black")
            y += h + 5
        return y

    y_position = 10
    y_position = draw_centered_text(draw, " ".join(patient_name), y_position, patient_name_font, max_width=label_width - 40)
    med_name_display, signature_info, split_occurred = split_med_name(med_name)
    if should_left_align(med_name_display):
        y_position = draw_left_aligned_text(draw, med_name_display, y_position, drug_name_font, max_width=label_width - 40)
        y_position = draw_centered_text(draw, f"({add_info})", y_position, info_font, max_width=label_width - 40)
    else:
        y_position = draw_centered_text(draw, med_name_display, y_position, drug_name_font, max_width=label_width - 40)
        y_position = draw_centered_text(draw, f"({add_info})", y_position, info_font, max_width=label_width - 40)
    if dosage and frequency and duration and unit:
        formatted_dosage = format_dosage(dosage)
        daily_dosage = dosage * frequency
        total_amount = daily_dosage * duration
        if round(dosage, 4) != round(dosage, 3):
            total_amount = round(total_amount * 4) / 4
        formatted_total_amount = str(int(total_amount)) if total_amount.is_integer() else f"{total_amount:.2f}".rstrip('0').rstrip('.')
        converted_total = format_converted_total(dosage, frequency, duration, conversion_factor)
        if converted_total is not None:
            total_label = f"총{formatted_total_amount}{unit}/{duration}일분({converted_total})"
        else:
            total_label = f"총{formatted_total_amount}{unit}/{duration}일분"
        y_position = draw_centered_text(draw, total_label, y_position, additional_info_font, max_width=label_width - 40)
        box_height = 70
        box_margin = 10
        box_width = label_width - 40
        box_x1 = (label_width - box_width) // 2
        box_x2 = box_x1 + box_width
        box_y1 = y_position + box_margin
        box_y2 = box_y1 + box_height
        draw.rectangle([box_x1, box_y1, box_x2, box_y2], outline="black", width=2)
        box_padding = 10
        line_spacing = 5
        box_text1 = f"{formatted_dosage}{unit}"
        text1_size = info_font.getbbox(box_text1)
        text1_height = text1_size[3] - text1_size[1]
        frequency_text = custom_dosage_instruction.strip()
        if not frequency_text:
            if frequency == 1:
                frequency_text = "아침"
            elif frequency == 2:
                frequency_text = "아침, 저녁"
            elif frequency == 3:
                frequency_text = "아침, 점심, 저녁"
        text2_height = 0
        if frequency_text:
            text2_size = info_font.getbbox(frequency_text)
            text2_height = text2_size[3] - text2_size[1]
        total_text_height = text1_height + line_spacing + text2_height
        center_y = (box_y1 + box_y2) // 2
        adjustment = 7
        start_y = center_y - (total_text_height // 2) - adjustment
        y_temp = draw_centered_text(draw, box_text1, start_y, info_font, max_width=box_width)
        if frequency_text:
            text2_y = y_temp + line_spacing
            draw_centered_text(draw, frequency_text, text2_y, info_font, max_width=box_width)
        y_position = box_y2 + box_margin
    if storage_condition:
        storage_condition_text = f"{storage_condition}"
        y_position = draw_centered_text(draw, storage_condition_text, y_position, storage_condition_font, max_width=label_width - 40)
    print_date_text = f"조제일 : {datetime.datetime.now(KOR_TZ).strftime('%Y-%m-%d')}"
    bbox = draw.textbbox((0, 0), print_date_text, font=print_date_font)
    w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
    print_date_x = (label_width - w) / 2
    print_date_y = label_height - h - 70
    draw.text((print_date_x, print_date_y), print_date_text, font=print_date_font, fill="black")
    signature_text = signature_info if signature_info else "청 춘 약 국"
    margin_val = int(0.1 * label_width)
    box_width_sig = label_width - 2 * margin_val
    try:
        bbox = draw.textbbox((0, 0), signature_text, font=signature_font)
        w_sig, h_sig = bbox[2] - bbox[0], bbox[3] - bbox[1]
        scale_factor = box_width_sig / w_sig if w_sig != 0 else 1
        scaled_font_size = max(1, int(22 * scale_factor))
        scaled_font = ImageFont.truetype(font_path, scaled_font_size)
    except IOError:
        scaled_font = ImageFont.load_default()
        logging.warning("시그니처 폰트 로드 실패. 기본 폰트 사용.")
    bbox = draw.textbbox((0, 0), signature_text, font=scaled_font)
    w_sig, h_sig = bbox[2] - bbox[0], bbox[3] - bbox[1]

    # 테두리 여백 설정
    padding_top = int(h_sig * 0.1)   # 위쪽 여백: 텍스트 높이의 10%
    padding_bottom = int(h_sig * 0.5)  # 아래쪽 여백: 텍스트 높이의 50%
    padding_sides = int(h_sig * 0.2)  # 좌우 여백: 텍스트 높이의 20%

    # 테두리 좌표 계산
    box_x = (label_width - w_sig) / 2 - padding_sides
    box_y = label_height - h_sig - padding_top - padding_bottom - 10
    box_x2 = box_x + w_sig + 2 * padding_sides
    box_y2 = box_y + h_sig + padding_top + padding_bottom
    draw.rectangle([(box_x, box_y), (box_x2, box_y2)], outline="black")
    draw.text(((label_width - w_sig) / 2, box_y + padding_top), signature_text, font=scaled_font, fill="black")
    draw_scissor_border(draw, label_width, label_height, edge_size=10, steps=20)
    return image


def print_label(patient_name, med_name, add_info, frequency, dosage, duration,
                formulation_type, main_ingredient_code, dosage_form, administration_route, label_name,
                unit=None, conversion_factor=None, storage_condition="실온보관", custom_dosage_instruction=""):
    """
    라벨 이미지를 생성하여 프린터로 인쇄합니다.

    Parameters:
        patient_name (str): 환자 이름
        med_name (str): 약품 이름
        add_info (str): 약품 효능 정보
        frequency (int): 복용 횟수
        dosage (float): 복용량
        duration (int): 복용 일수
        formulation_type (str): 제형 타입
        main_ingredient_code (str): 주성분 코드 
        dosage_form (str): 복용 형태
        administration_route (str): 투여 경로
        label_name (str): 라벨 명칭
        unit (str, optional): 복용 단위
        conversion_factor (float, optional): 환산계수
        storage_condition (str, optional): 보관 조건
        custom_dosage_instruction (str, optional): 커스텀 용법 텍스트
    """
    try:
        if not unit:
            if "캡슐" in med_name:
                unit = "캡슐"
            elif "정" in med_name:
                unit = "정"
            elif "시럽" in med_name:
                unit = "ml"
            elif "과립" in med_name or "시럽" in med_name:
                unit = "g"
            else:
                unit = "개"
        label_image = create_label_image(
            patient_name=patient_name,
            med_name=med_name,
            add_info=add_info,
            frequency=frequency,
            dosage=dosage,
            duration=duration,
            formulation_type=formulation_type,
            main_ingredient_code=main_ingredient_code,
            dosage_form=dosage_form,
            administration_route=administration_route,
            label_name=label_name,
            unit=unit,
            conversion_factor=conversion_factor,
            storage_condition=storage_condition,
            custom_dosage_instruction=custom_dosage_instruction
        )
        image_stream = io.BytesIO()
        label_image.save(image_stream, format="PNG")
        image_stream.seek(0)
        from brother_ql.raster import BrotherQLRaster
        from brother_ql.conversion import convert
        from brother_ql.backends.helpers import send

        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"라벨 인쇄 성공: 환자={patient_name}, 약품={med_name}, 커스텀 용법={custom_dosage_instruction}")
        print(f"[SUCCESS] 라벨 인쇄 성공: 환자={patient_name}, 약품={med_name}, 커스텀 용법={custom_dosage_instruction}")
    except Exception as e:
        logging.error(f"라벨 인쇄 실패: {e}")
        print(f"[ERROR] 라벨 인쇄 실패: {e}")


def print_custom_image(pil_image):
    """
    PIL 이미지를 받아 Brother QL 프린터로 인쇄합니다.

    Parameters:
        pil_image (PIL.Image): 인쇄할 이미지
    """
    try:
        logging.info(f"이미지 모드: {pil_image.mode}")
        if pil_image.mode in ('RGBA', 'LA'):
            logging.info("알파 채널 있음 (RGBA 또는 LA 모드)")
        elif pil_image.mode == 'P' and 'transparency' in pil_image.info:
            logging.info("알파 채널 있음 (팔레트 모드, transparency 키 확인됨)")
        else:
            logging.info("알파 채널 없음")
        pil_image = pil_image.rotate(90, expand=True)
        width, height = pil_image.size
        new_height = int((306 / width) * height)
        pil_image = pil_image.resize((306, new_height), Image.LANCZOS)
        if pil_image.mode in ('RGBA', 'LA') or (pil_image.mode == 'P' and 'transparency' in pil_image.info):
            background = Image.new("RGB", pil_image.size, "white")
            background.paste(pil_image, mask=pil_image.split()[-1])
            pil_image = background
        image_stream = io.BytesIO()
        pil_image.convert('1').save(image_stream, format="PNG")
        image_stream.seek(0)
        from brother_ql.raster import BrotherQLRaster
        from brother_ql.conversion import convert
        from brother_ql.backends.helpers import send

        # 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("커스텀 이미지 인쇄 성공")
        print("[SUCCESS] 커스텀 이미지 인쇄 성공")
    except Exception as e:
        logging.error(f"커스텀 이미지 인쇄 실패: {e}")
        print(f"[ERROR] 커스텀 이미지 인쇄 실패: {e}")


if __name__ == "__main__":
    # 인터랙티브 메뉴를 통해 샘플 인쇄 선택

    samples = {
        "1": {
            "patient_name": "이영희",
            "med_name": "아모크라정375mg",
            "add_info": "고혈압",
            "frequency": 1,
            "dosage": 375.0,
            "duration": 30,
            "formulation_type": "정제",
            "main_ingredient_code": "AMO375",
            "dosage_form": "경구",
            "administration_route": "경구",
            "label_name": "고혈압용",
            "unit": None,
            "conversion_factor": 1.0,
            "storage_condition": "실온보관",
            "custom_dosage_instruction": ""
        },
        "2": {
            "patient_name": "박지성",
            "med_name": "삼남아세트아미노펜정500mg",
            "add_info": "통증 완화",
            "frequency": 2,
            "dosage": 500.0,
            "duration": 5,
            "formulation_type": "정제",
            "main_ingredient_code": "MED001",  # 예시용
            "dosage_form": "경구",
            "administration_route": "경구",
            "label_name": "통증용",
            "unit": None,
            "conversion_factor": 1.0,
            "storage_condition": "서늘한 곳에 보관",
            "custom_dosage_instruction": ""
        },
        "3": {
            "patient_name": "최민수",
            "med_name": "세레타이드125에보할러",
            "add_info": "알레르기 치료",
            "frequency": 3,
            "dosage": 125.0,
            "duration": 10,
            "formulation_type": "정제",
            "main_ingredient_code": "SER125",
            "dosage_form": "흡입",
            "administration_route": "흡입",
            "label_name": "알레르기용",
            "unit": None,
            "conversion_factor": 1.0,
            "storage_condition": "냉장보관",
            "custom_dosage_instruction": ""
        },
        "4": {
            "patient_name": "최민수",
            "med_name": "트윈스타정40/5mg",
            "add_info": "혈압 조절",
            "frequency": 2,
            "dosage": 40.0,
            "duration": 10,
            "formulation_type": "정제",
            "main_ingredient_code": "TW40",
            "dosage_form": "경구",
            "administration_route": "경구",
            "label_name": "고혈압용",
            "unit": None,
            "conversion_factor": 1.0,
            "storage_condition": "실온보관",
            "custom_dosage_instruction": ""
        },
        "5": {
            "patient_name": "최우주",
            "med_name": "오셀타원현탁용분말6mg/mL",
            "add_info": "오셀타미",
            "frequency": 2,
            "dosage": 4.0,
            "duration": 5,
            "formulation_type": "현탁용분말",
            "main_ingredient_code": "358907ASS",
            "dosage_form": "SS",
            "administration_route": "A",
            "label_name": "오셀타원현탁용분말6mg/mL",
            "unit": "ml",
            "conversion_factor": 0.126,
            "storage_condition": "실온및(냉장)",
            "custom_dosage_instruction": ""
        },
        "6": {
            "patient_name": "최우주",
            "med_name": "어린이타이레놀현탁액",
            "add_info": "해열,진통제",
            "frequency": 3,
            "dosage": 3.0,
            "duration": 3,
            "formulation_type": "현탁액",
            "main_ingredient_code": "101330ASS",
            "dosage_form": "SS",
            "administration_route": "A",
            "label_name": "어린이타이레놀현탁액",
            "unit": "ml",
            "conversion_factor": None,
            "storage_condition": "실온보관",
            "custom_dosage_instruction": ""
        }
    }

    print("=======================================")
    print("           라벨 인쇄 샘플 선택           ")
    print("=======================================")
    for key, sample in samples.items():
        print(f"{key}: {sample['patient_name']} / {sample['med_name']} / {sample['add_info']}")
    print("q: 종료")
    
    choice = input("인쇄할 샘플 번호를 선택하세요: ").strip()
    while choice.lower() != 'q':
        if choice in samples:
            sample = samples[choice]
            print(f"선택한 샘플: {sample['patient_name']} / {sample['med_name']}")
            print_label(
                patient_name=sample["patient_name"],
                med_name=sample["med_name"],
                add_info=sample["add_info"],
                frequency=sample["frequency"],
                dosage=sample["dosage"],
                duration=sample["duration"],
                formulation_type=sample["formulation_type"],
                main_ingredient_code=sample["main_ingredient_code"],
                dosage_form=sample["dosage_form"],
                administration_route=sample["administration_route"],
                label_name=sample["label_name"],
                unit=sample["unit"],
                conversion_factor=sample["conversion_factor"],
                storage_condition=sample["storage_condition"],
                custom_dosage_instruction=sample["custom_dosage_instruction"]
            )
        else:
            print("올바른 번호를 입력하세요.")
        choice = input("인쇄할 샴플 번호를 선택하세요 (종료하려면 q 입력): ").strip()


# ==================================================================================
# 약품 QR 라벨 인쇄 기능 (신규 추가)
# ==================================================================================
# 목적: 약품 검색 후 바코드 기반 QR 코드, 약품명, 판매가격이 포함된 라벨 인쇄
# 기존 처방전 라벨 인쇄 기능과 완전히 분리된 독립 기능
# ==================================================================================

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

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

    Returns:
        PIL.Image: 생성된 라벨 이미지

    라벨 구조 (3단):
    ┌─────────────────┐
    │   [QR CODE]     │  ← 바코드 기반 QR 코드 (상단)
    ├─────────────────┤
    │   약품명         │  ← 중앙 정렬 (중간)
    ├─────────────────┤
    │   ₩12,000       │  ← 판매가격 (하단)
    └─────────────────┘
    """
    # 라벨 크기 설정 (29mm 용지 기준)
    label_width = 306
    label_height = 380
    image = Image.new("1", (label_width, label_height), "white")
    draw = ImageDraw.Draw(image)

    # 폰트 설정
    font_path = "/srv/for-windows/person-lookup-web/prescription_monitoring/malgunbd.ttf"
    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  # 180 → 130으로 축소
    qr_img = qr_img.resize((qr_size, qr_size), Image.LANCZOS)
    qr_x = (label_width - qr_size) // 2
    qr_y = 15  # 상단 여백 약간 줄임

    # QR 코드를 메인 이미지에 붙이기
    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  # 간격 줄임

    # 약품명이 길면 2줄로 나누기 (괄호 기준 자동 분리)
    def draw_wrapped_text(draw, text, y, font, max_width):
        """
        약품명을 2줄로 표시하되, 괄호가 있으면 괄호 앞뒤로 자동 분리

        예시:
        - "안텔민뽀삐(5kg이하)" → ["안텔민뽀삐", "(5kg이하)"]
        - "타이레놀정500mg" → 폭 기준으로 자동 분리
        """
        import re

        lines = []

        # 괄호가 있으면 괄호 기준으로 먼저 분리
        if '(' in text and ')' in text:
            # 괄호 앞부분과 괄호 포함 뒷부분으로 분리
            match = re.match(r'^(.+?)(\(.+\))$', text)
            if match:
                main_part = match.group(1).strip()
                bracket_part = match.group(2).strip()

                # 첫 줄이 max_width를 초과하면 글자 단위로 자르기
                bbox = draw.textbbox((0, 0), main_part, font=font)
                w = bbox[2] - bbox[0]

                if w <= max_width:
                    # 괄호 앞 부분이 한 줄에 들어감
                    lines.append(main_part)
                    lines.append(bracket_part)
                else:
                    # 괄호 앞 부분이 너무 길면 글자 단위로 자르기
                    chars = list(main_part)
                    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)

                    # 괄호 부분 추가 (최대 2줄이므로 1개만)
                    if len(lines) < 2:
                        lines.append(bracket_part)
            else:
                # 괄호 패턴 매칭 실패 시 기존 로직
                lines = _split_text_by_width(draw, text, font, max_width)
        else:
            # 괄호가 없으면 폭 기준으로 자동 분리
            lines = _split_text_by_width(draw, text, font, max_width)

        # 최대 2줄만 표시
        lines = lines[: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

    def _split_text_by_width(draw, text, 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)

        return lines

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

    # 약간의 여백
    y_position += 8

    # 가격 그리기 (약품명 바로 아래)
    if 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 += 12

    # 청춘약국 서명 (하단에 고정하지 않고 가격 아래 배치)
    signature_text = "청 춘 약 국"
    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 - padding
    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, y_position), signature_text, font=label_font, fill="black")

    # 절취선 테두리
    draw_scissor_border(draw, label_width, label_height, edge_size=10, steps=20)

    return image


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

    Parameters:
        drug_name (str): 약품명
        barcode (str): 바코드
        sale_price (float): 판매가격
        drug_code (str, optional): 약품 코드
    """
    try:
        label_image = create_drug_qr_label(drug_name, barcode, sale_price, drug_code)

        # 이미지를 메모리 스트림으로 변환
        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}, 가격={sale_price}")
        print(f"[SUCCESS] 약품 QR 라벨 인쇄 성공: {drug_name}")
        return True

    except Exception as e:
        logging.error(f"약품 QR 라벨 인쇄 실패: {e}")
        print(f"[ERROR] 약품 QR 라벨 인쇄 실패: {e}")
        return False


# ==================================================================================
# 약품 QR 라벨 인쇄 기능 끝
# ==================================================================================


# ==================================================================================
# 상품 라벨 인쇄 기능 (v2.0 - 효과/용법/꿀팁 포함)
# ==================================================================================

def create_product_label(drug_name, effect="", dosage_instruction="", usage_tip=""):
    """
    상품 라벨 이미지 생성

    Parameters:
        drug_name (str): 약품명 (필수)
        effect (str): 효과 (예: "치통약")
        dosage_instruction (str): 용법 (예: "2정 또는 3정 복용...")
        usage_tip (str): 복용 꿀팁 (예: "이튼돌과 함께...")

    Returns:
        PIL.Image: 생성된 라벨 이미지 (306x400px, mode='1')
    """
    # 라벨 크기 설정
    label_width = 306
    label_height = 400
    image = Image.new("1", (label_width, label_height), "white")
    draw = ImageDraw.Draw(image)

    # 폰트 설정
    font_path = "/srv/for-windows/person-lookup-web/prescription_monitoring/malgunbd.ttf"
    try:
        drug_name_font = ImageFont.truetype(font_path, 32)
        label_font = ImageFont.truetype(font_path, 24)
        tip_font = ImageFont.truetype(font_path, 22)
        signature_font = ImageFont.truetype(font_path, 24)
    except IOError:
        drug_name_font = ImageFont.load_default()
        label_font = ImageFont.load_default()
        tip_font = ImageFont.load_default()
        signature_font = ImageFont.load_default()
        logging.warning("폰트 로드 실패. 기본 폰트 사용.")

    # 좌측 정렬 텍스트 출력 함수
    def draw_left_aligned_text(draw, text, y, font, max_width=266, max_lines=4):
        if not text:
            return y

        lines = []
        current_line = ""

        # 텍스트를 줄바꿈 기준으로 먼저 분리
        text_lines = text.split('\n')

        for text_line in text_lines:
            # 각 줄을 글자 단위로 처리
            for char in text_line:
                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)
                current_line = ""

        # 최대 줄 수 제한
        lines = lines[:max_lines]

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

        return y

    # 중앙 정렬 텍스트 출력 함수
    def draw_centered_text(draw, text, y, font, max_width=286, max_lines=2):
        if not text:
            return y

        lines = []
        current_line = ""

        for char in text:
            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[:max_lines]

        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 = 15

    # 1. 약품명 (중앙 정렬, 최대 2줄)
    y_position = draw_centered_text(draw, drug_name, y_position, drug_name_font, max_width=286, max_lines=2)
    y_position += 10

    # 구분선
    draw.line([(30, y_position), (276, y_position)], fill="black", width=2)
    y_position += 10

    # 2. 효과 (좌측 정렬, 최대 2줄)
    if effect:
        effect_text = f"효과: {effect}"
        y_position = draw_left_aligned_text(draw, effect_text, y_position, label_font, max_width=266, max_lines=2)
        y_position += 8

    # 3. 용법 (좌측 정렬, 최대 4줄)
    if dosage_instruction:
        dosage_text = f"용법:\n{dosage_instruction}"
        y_position = draw_left_aligned_text(draw, dosage_text, y_position, label_font, max_width=266, max_lines=4)
        y_position += 8

    # 구분선
    if usage_tip:
        draw.line([(30, y_position), (276, y_position)], fill="black", width=2)
        y_position += 10

    # 4. 복용 꿀팁 (좌측 정렬, 최대 4줄)
    if usage_tip:
        tip_text = f"💡 복용 꿀팁:\n{usage_tip}"
        y_position = draw_left_aligned_text(draw, tip_text, y_position, tip_font, max_width=266, max_lines=4)
        y_position += 12

    # 구분선
    draw.line([(30, y_position), (276, y_position)], fill="black", width=2)
    y_position += 15

    # 5. 청춘약국 서명 (하단 고정, 테두리 박스)
    signature_text = "청 춘 약 국"
    bbox = draw.textbbox((0, 0), signature_text, font=signature_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 = label_height - h_sig - 40
    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=signature_font, fill="black")

    # 6. 절취선 테두리
    draw_scissor_border(draw, label_width, label_height, edge_size=10, steps=20)

    return image


def print_product_label(drug_name, effect="", dosage_instruction="", usage_tip=""):
    """
    상품 라벨 인쇄 실행

    Parameters:
        drug_name (str): 약품명
        effect (str): 효과
        dosage_instruction (str): 용법
        usage_tip (str): 복용 꿀팁

    Returns:
        bool: 인쇄 성공 여부
    """
    try:
        label_image = create_product_label(drug_name, effect, dosage_instruction, usage_tip)

        # 이미지를 메모리 스트림으로 변환
        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"상품 라벨 인쇄 성공: {drug_name}")
        print(f"[SUCCESS] 상품 라벨 인쇄 성공: {drug_name}")
        return True

    except Exception as e:
        logging.error(f"상품 라벨 인쇄 실패: {e}")
        print(f"[ERROR] 상품 라벨 인쇄 실패: {e}")
        return False


def create_product_label_wide(drug_name, effect="", dosage_instruction="", usage_tip=""):
    """
    가로형 와이드 상품 라벨 이미지 생성 (800 x 306px)

    레이아웃 구조:
    - 효능: 중앙 상단에 크게 강조
    - 약품명: 오른쪽 여백 공간에 배치
    - 용법: 왼쪽 하단에 크게
    - 약국명: 오른쪽 하단에 크게

    Args:
        drug_name (str): 약품명
        effect (str): 효능
        dosage_instruction (str): 복용 방법
        usage_tip (str): 사용 팁

    Returns:
        PIL.Image: 가로형 와이드 라벨 이미지 (800 x 306px, mode='1')
    """
    try:
        # 1. 캔버스 생성 (가로로 긴 형태, 고정 800px)
        width = 800
        height = 306  # Brother QL 29mm 용지 폭

        img = Image.new('1', (width, height), 1)  # 흰색 배경
        draw = ImageDraw.Draw(img)

        # 2. 폰트 로드 (새로운 레이아웃에 맞게 최적화)
        font_path = "/srv/for-windows/person-lookup-web/prescription_monitoring/malgunbd.ttf"
        try:
            font_effect = ImageFont.truetype(font_path, 72)  # 효능 (매우 크게!)
            font_drugname = ImageFont.truetype(font_path, 36)  # 약품명 (중간)
            font_dosage = ImageFont.truetype(font_path, 40)  # 용법 (크게)
            font_pharmacy = ImageFont.truetype(font_path, 32)  # 약국명 (크게)
            font_small = ImageFont.truetype(font_path, 26)   # 사용팁
        except IOError:
            font_effect = ImageFont.load_default()
            font_drugname = ImageFont.load_default()
            font_dosage = ImageFont.load_default()
            font_pharmacy = ImageFont.load_default()
            font_small = ImageFont.load_default()
            logging.warning("폰트 로드 실패. 기본 폰트 사용.")

        # 3. 레이아웃 (새로운 구조)
        x_margin = 25

        # 효능 - 중앙 상단에 크게 (매우 강조!)
        if effect:
            effect_bbox = draw.textbbox((0, 0), effect, font=font_effect)
            effect_width = effect_bbox[2] - effect_bbox[0]
            effect_x = (width - effect_width) // 2
            # 굵게 표시 (offset)
            for offset in [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)]:
                draw.text((effect_x + offset[0], 20 + offset[1]), effect, font=font_effect, fill=0)

        # 약품명 - 오른쪽 중간 여백에 배치 (테두리 없음)
        drugname_bbox = draw.textbbox((0, 0), drug_name, font=font_drugname)
        drugname_width = drugname_bbox[2] - drugname_bbox[0]
        drugname_x = width - drugname_width - 30  # 오른쪽에서 30px 여백
        drugname_y = 195  # 조금 더 아래로
        draw.text((drugname_x, drugname_y), drug_name, font=font_drugname, fill=0)

        # 용법 - 왼쪽 하단에 크게 표시 (사용팁 유무에 따라 크기 조정)
        y = 120  # 효능 아래부터 시작

        # 사용팁이 없으면 복용방법을 더 크게
        if not usage_tip:
            font_dosage_adjusted = ImageFont.truetype(font_path, 50)  # 더 큰 폰트
        else:
            font_dosage_adjusted = font_dosage  # 기본 폰트 (40pt)

        if dosage_instruction:
            # 대괄호로 묶인 부분을 별도 줄로 분리
            import re
            # [텍스트] 패턴을 찾아서 줄바꿈으로 치환
            dosage_text = re.sub(r'\s*(\[.*?\])\s*', r'\n\1\n', dosage_instruction)

            # 여러 줄 처리
            max_chars_per_line = 32
            dosage_lines = []

            # 줄바꿈으로 먼저 분리
            text_parts = dosage_text.split('\n')

            for part in text_parts:
                part = part.strip()
                if not part:
                    continue

                # 대괄호로 묶인 부분은 그대로 한 줄로
                if part.startswith('[') and part.endswith(']'):
                    dosage_lines.append(part)
                # 일반 텍스트는 길이에 따라 분리
                elif len(part) > max_chars_per_line:
                    words = part.split()
                    current_line = ""
                    for word in words:
                        if len(current_line + word) <= max_chars_per_line:
                            current_line += word + " "
                        else:
                            if current_line:
                                dosage_lines.append(current_line.strip())
                            current_line = word + " "
                    if current_line:
                        dosage_lines.append(current_line.strip())
                else:
                    dosage_lines.append(part)

            # 첫 줄에 체크박스 추가 (조정된 폰트 사용)
            if dosage_lines:
                first_line = f"□ {dosage_lines[0]}"
                draw.text((x_margin, y), first_line, font=font_dosage_adjusted, fill=0)

                # 줄 간격 조정 (폰트 크기에 따라)
                line_spacing = 60 if not usage_tip else 50
                y += line_spacing

                # 나머지 줄 (조정된 폰트 및 간격 사용)
                for line in dosage_lines[1:]:
                    # 대괄호로 묶인 줄은 들여쓰기 없이
                    indent = 0 if (line.startswith('[') and line.endswith(']')) else 30
                    draw.text((x_margin + indent, y), line, font=font_dosage_adjusted, fill=0)
                    y += line_spacing + 2

        # 사용팁 (체크박스 + 텍스트)
        if usage_tip and y < height - 60:
            tip_text = f"□ {usage_tip}"
            # 길면 축약 (길이 제한 늘림)
            if len(tip_text) > 55:
                tip_text = tip_text[:52] + "..."
            draw.text((x_margin, y), tip_text, font=font_small, fill=0)

        # 약국명 - 오른쪽 하단에 크게 (테두리 박스)
        sign_text = "청춘약국"
        sign_bbox = draw.textbbox((0, 0), sign_text, font=font_pharmacy)
        sign_width = sign_bbox[2] - sign_bbox[0]
        sign_height = sign_bbox[3] - sign_bbox[1]

        # 패딩 설정 (상하 불균형 조정)
        sign_padding_lr = 10  # 좌우 패딩
        sign_padding_top = 5   # 상단 패딩 (줄임)
        sign_padding_bottom = 10  # 하단 패딩

        sign_x = width - sign_width - x_margin - 10 - sign_padding_lr
        sign_y = height - 55  # 위치 고정

        # 테두리 박스 그리기 (상단 패딩만 줄임)
        box_x1 = sign_x - sign_padding_lr
        box_y1 = sign_y - sign_padding_top
        box_x2 = sign_x + sign_width + sign_padding_lr
        box_y2 = sign_y + sign_height + sign_padding_bottom
        draw.rectangle([box_x1, box_y1, box_x2, box_y2], outline=0, width=2)

        # 약국명 텍스트 (굵게)
        for offset in [(0, 0), (1, 0), (0, 1), (1, 1)]:
            draw.text((sign_x + offset[0], sign_y + offset[1]), sign_text, font=font_pharmacy, fill=0)

        # 5. 테두리 (가위선 스타일)
        for i in range(3):
            draw.rectangle([5 + i, 5 + i, width - 5 - i, height - 5 - i], outline=0)

        logging.info(f"가로형 와이드 라벨 이미지 생성 성공: {drug_name}")
        return img

    except Exception as e:
        logging.error(f"가로형 와이드 라벨 이미지 생성 실패: {e}")
        raise


def print_product_label_wide(drug_name, effect="", dosage_instruction="", usage_tip=""):
    """
    가로형 와이드 상품 라벨 인쇄

    이미지를 90도 회전하여 Brother QL 프린터로 전송

    Args:
        drug_name (str): 약품명
        effect (str): 효능
        dosage_instruction (str): 복용 방법
        usage_tip (str): 사용 팁

    Returns:
        bool: 성공 여부
    """
    try:
        # 1. 가로형 라벨 이미지 생성
        label_img = create_product_label_wide(drug_name, effect, dosage_instruction, usage_tip)

        # 2. 이미지 90도 회전 (Brother QL이 세로 방향 기준이므로)
        # 시계 반대방향 90도 회전
        label_img_rotated = label_img.rotate(90, expand=True)

        logging.info(f"이미지 회전 완료: {label_img_rotated.size}")

        # 3. Brother QL 프린터로 전송
        qlr = BrotherQLRaster(PRINTER_MODEL)
        instructions = convert(
            qlr=qlr,
            images=[label_img_rotated],
            label='29',  # 29mm 용지
            rotate='0',  # 이미 회전했으므로 0
            threshold=70.0,
            dither=False,
            compress=False,
            red=False,
            dpi_600=False,
            hq=True,
            cut=True
        )
        send(instructions, printer_identifier=f"tcp://{PRINTER_IP}:9100")

        logging.info(f"[SUCCESS] 가로형 와이드 상품 라벨 인쇄 성공: {drug_name}")
        print(f"[SUCCESS] 가로형 와이드 상품 라벨 인쇄 성공: {drug_name}")
        return True

    except Exception as e:
        logging.error(f"[ERROR] 가로형 와이드 라벨 인쇄 실패: {e}")
        print(f"[ERROR] 가로형 와이드 라벨 인쇄 실패: {e}")
        return False


# ==================================================================================
# 상품 라벨 인쇄 기능 끝
# ==================================================================================