"""
ESC/POS QR 코드 인쇄 방식 테스트
여러 가지 방법을 한 번에 시도하여 어떤 방식이 작동하는지 확인
"""

import socket
import qrcode
import time
from PIL import Image

# 프린터 설정 (고정)
PRINTER_IP = "192.168.0.174"
PRINTER_PORT = 9100

# 테스트 URL (짧은 버전)
TEST_URL = "https://mile.0bin.in/test"


def send_to_printer(data, method_name):
    """프린터로 데이터 전송"""
    try:
        print(f"\n{'='*60}")
        print(f"[{method_name}] 전송 시작...")
        print(f"데이터 크기: {len(data)} bytes")

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((PRINTER_IP, PRINTER_PORT))
        sock.sendall(data)
        sock.close()

        print(f"[{method_name}] ✅ 전송 완료!")
        time.sleep(2)  # 프린터 처리 대기
        return True
    except Exception as e:
        print(f"[{method_name}] ❌ 실패: {e}")
        return False


def method_1_native_qr_model2():
    """
    방법 1: 프린터 내장 QR 생성 (GS ( k) - Model 2
    가장 안정적이지만 프린터 지원 필요
    """
    ESC = b'\x1b'
    GS = b'\x1d'

    commands = []

    # 초기화
    commands.append(ESC + b'@')

    # 헤더
    commands.append("\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("     *** 방법 1 ***\n".encode('euc-kr'))
    commands.append("  내장 QR (GS ( k)\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("\n".encode('euc-kr'))

    # QR 설정
    # GS ( k pL pH cn fn n (QR Code)
    # cn = 49 (Model 1/2 선택)
    # fn = 65 (모델 선택)
    # n = 50 (Model 2)

    # 모델 설정
    commands.append(GS + b'(k' + bytes([3, 0, 49, 65, 50]))  # Model 2

    # 에러 정정 레벨 설정 (fn=69, n=48=L)
    commands.append(GS + b'(k' + bytes([3, 0, 49, 69, 48]))

    # 모듈 크기 설정 (fn=67, n=8)
    commands.append(GS + b'(k' + bytes([3, 0, 49, 67, 8]))

    # QR 데이터 저장 (fn=80)
    qr_data = TEST_URL.encode('utf-8')
    data_len = len(qr_data) + 3
    pL = data_len & 0xFF
    pH = (data_len >> 8) & 0xFF
    commands.append(GS + b'(k' + bytes([pL, pH, 49, 80, 48]) + qr_data)

    # QR 인쇄 (fn=81)
    commands.append(GS + b'(k' + bytes([3, 0, 49, 81, 48]))

    # 푸터
    commands.append("\n".encode('euc-kr'))
    commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
    commands.append("\n\n\n".encode('euc-kr'))

    # 용지 커트
    commands.append(GS + b'V' + bytes([1]))

    return b''.join(commands)


def method_2_raster_bitmap_gs_v():
    """
    방법 2: Raster Bit Image (GS v 0)
    """
    ESC = b'\x1b'
    GS = b'\x1d'

    commands = []

    # 초기화
    commands.append(ESC + b'@')

    # 헤더
    commands.append("\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("     *** 방법 2 ***\n".encode('euc-kr'))
    commands.append("  Raster (GS v 0)\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("\n".encode('euc-kr'))

    # QR 이미지 생성 (작게: 80x80)
    qr = qrcode.QRCode(version=1, box_size=2, border=2)
    qr.add_data(TEST_URL)
    qr.make(fit=True)
    qr_image = qr.make_image(fill_color="black", back_color="white")
    qr_image = qr_image.resize((80, 80))

    # 1비트 흑백으로 변환
    qr_image = qr_image.convert('1')
    width, height = qr_image.size
    pixels = qr_image.load()

    # GS v 0 명령어
    width_bytes = (width + 7) // 8
    commands.append(GS + b'v0' + bytes([0]))  # 보통 모드
    commands.append(bytes([width_bytes & 0xFF, (width_bytes >> 8) & 0xFF]))  # xL, xH
    commands.append(bytes([height & 0xFF, (height >> 8) & 0xFF]))  # yL, yH

    # 이미지 데이터
    for y in range(height):
        for x in range(0, width, 8):
            byte = 0
            for bit in range(8):
                if x + bit < width:
                    if pixels[x + bit, y] == 0:  # 검은색
                        byte |= (1 << (7 - bit))
            commands.append(bytes([byte]))

    # 푸터
    commands.append("\n".encode('euc-kr'))
    commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
    commands.append("\n\n\n".encode('euc-kr'))

    # 용지 커트
    commands.append(GS + b'V' + bytes([1]))

    return b''.join(commands)


def method_3_bit_image_esc_star():
    """
    방법 3: Bit Image (ESC *) - 24-dot double-density
    현재 사용 중인 방식
    """
    ESC = b'\x1b'
    GS = b'\x1d'

    commands = []

    # 초기화
    commands.append(ESC + b'@')

    # 헤더
    commands.append("\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("     *** 방법 3 ***\n".encode('euc-kr'))
    commands.append("  Bit Image (ESC *)\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("\n".encode('euc-kr'))

    # QR 이미지 생성 (작게: 80x80)
    qr = qrcode.QRCode(version=1, box_size=2, border=2)
    qr.add_data(TEST_URL)
    qr.make(fit=True)
    qr_image = qr.make_image(fill_color="black", back_color="white")
    qr_image = qr_image.resize((80, 80))

    # 1비트 흑백으로 변환
    qr_image = qr_image.convert('1')
    width, height = qr_image.size
    pixels = qr_image.load()

    # ESC * 명령어로 라인별 인쇄
    for y in range(0, height, 24):
        line_height = min(24, height - y)

        # ESC * m nL nH
        nL = width & 0xFF
        nH = (width >> 8) & 0xFF
        commands.append(ESC + b'*' + bytes([33, nL, nH]))  # m=33 (24-dot double-density)

        # 라인 데이터
        for x in range(width):
            byte1, byte2, byte3 = 0, 0, 0

            for bit in range(line_height):
                pixel_y = y + bit
                if pixel_y < height:
                    if pixels[x, pixel_y] == 0:  # 검은색
                        if bit < 8:
                            byte1 |= (1 << (7 - bit))
                        elif bit < 16:
                            byte2 |= (1 << (15 - bit))
                        else:
                            byte3 |= (1 << (23 - bit))

            commands.append(bytes([byte1, byte2, byte3]))

        commands.append(b'\n')

    # 푸터
    commands.append("\n".encode('euc-kr'))
    commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
    commands.append("\n\n\n".encode('euc-kr'))

    # 용지 커트
    commands.append(GS + b'V' + bytes([1]))

    return b''.join(commands)


def method_4_simple_text_only():
    """
    방법 4: 텍스트만 (비교용)
    """
    ESC = b'\x1b'
    GS = b'\x1d'

    commands = []

    # 초기화
    commands.append(ESC + b'@')

    # 헤더
    commands.append("\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("     *** 방법 4 ***\n".encode('euc-kr'))
    commands.append("  텍스트만 (비교용)\n".encode('euc-kr'))
    commands.append("================================\n".encode('euc-kr'))
    commands.append("\n".encode('euc-kr'))
    commands.append("QR 이미지 대신 URL만 출력\n".encode('euc-kr'))
    commands.append("\n".encode('euc-kr'))
    commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
    commands.append("\n\n\n".encode('euc-kr'))

    # 용지 커트
    commands.append(GS + b'V' + bytes([1]))

    return b''.join(commands)


def main():
    """메인 실행"""
    print("="*60)
    print("ESC/POS QR 코드 인쇄 방식 테스트")
    print("="*60)
    print(f"프린터: {PRINTER_IP}:{PRINTER_PORT}")
    print(f"테스트 URL: {TEST_URL}")
    print("="*60)

    methods = [
        ("방법 1: 프린터 내장 QR (GS ( k)", method_1_native_qr_model2),
        ("방법 2: Raster Bitmap (GS v 0)", method_2_raster_bitmap_gs_v),
        ("방법 3: Bit Image (ESC *)", method_3_bit_image_esc_star),
        ("방법 4: 텍스트만", method_4_simple_text_only),
    ]

    results = []

    for name, method_func in methods:
        try:
            data = method_func()
            success = send_to_printer(data, name)
            results.append((name, success))
        except Exception as e:
            print(f"[{name}] ❌ 함수 실행 오류: {e}")
            results.append((name, False))

    # 결과 요약
    print("\n" + "="*60)
    print("테스트 결과 요약")
    print("="*60)
    for name, success in results:
        status = "✅ 성공" if success else "❌ 실패"
        print(f"{name}: {status}")

    print("\n인쇄된 영수증을 확인하여 어떤 방법이 QR을 제대로 출력했는지 확인하세요!")
    print("="*60)


if __name__ == "__main__":
    main()
