"""
ESC/POS QR 코드 인쇄 방식 테스트 v2
더 많은 변형 시도 (크기, 밀도, 파라미터)
"""

import socket
import qrcode
import time

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

# 테스트 URL (더 짧게)
TEST_URL = "https://bit.ly/test"


def send_to_printer(data, method_name):
    """프린터로 데이터 전송"""
    try:
        print(f"\n[{method_name}] 전송 중... ({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(1.5)
        return True
    except Exception as e:
        print(f"[{method_name}] ❌ 실패: {e}")
        return False


def method_1_tiny_qr_escstar():
    """방법 1: 아주 작은 QR (30x30) + ESC *"""
    ESC = b'\x1b'
    GS = b'\x1d'
    commands = []
    commands.append(ESC + b'@')
    commands.append("\n================================\n".encode('euc-kr'))
    commands.append("     *** 방법 1 ***\n".encode('euc-kr'))
    commands.append("  작은 QR 30x30 (ESC *)\n".encode('euc-kr'))
    commands.append("================================\n\n".encode('euc-kr'))

    # 30x30 QR
    qr = qrcode.QRCode(version=1, box_size=1, border=1)
    qr.add_data(TEST_URL)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white").resize((30, 30)).convert('1')
    width, height = img.size
    pixels = img.load()

    # ESC * m=0 (8-dot single-density)
    for y in range(0, height, 8):
        commands.append(ESC + b'*' + bytes([0, width & 0xFF, (width >> 8) & 0xFF]))
        for x in range(width):
            byte = 0
            for bit in range(min(8, height - y)):
                if pixels[x, y + bit] == 0:
                    byte |= (1 << (7 - bit))
            commands.append(bytes([byte]))
        commands.append(b'\n')

    commands.append(f"\nURL: {TEST_URL}\n\n\n".encode('euc-kr'))
    commands.append(GS + b'V' + bytes([1]))
    return b''.join(commands)


def method_2_medium_qr_escstar_mode32():
    """방법 2: 중간 QR (50x50) + ESC * mode 32"""
    ESC = b'\x1b'
    GS = b'\x1d'
    commands = []
    commands.append(ESC + b'@')
    commands.append("\n================================\n".encode('euc-kr'))
    commands.append("     *** 방법 2 ***\n".encode('euc-kr'))
    commands.append("  중간 QR 50x50 (ESC * m=32)\n".encode('euc-kr'))
    commands.append("================================\n\n".encode('euc-kr'))

    # 50x50 QR
    qr = qrcode.QRCode(version=1, box_size=2, border=1)
    qr.add_data(TEST_URL)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white").resize((50, 50)).convert('1')
    width, height = img.size
    pixels = img.load()

    # ESC * m=32 (24-dot single-density)
    for y in range(0, height, 24):
        commands.append(ESC + b'*' + bytes([32, width & 0xFF, (width >> 8) & 0xFF]))
        for x in range(width):
            byte1 = byte2 = byte3 = 0
            for bit in range(min(24, height - y)):
                if pixels[x, y + bit] == 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(f"\nURL: {TEST_URL}\n\n\n".encode('euc-kr'))
    commands.append(GS + b'V' + bytes([1]))
    return b''.join(commands)


def method_3_native_qr_simple():
    """방법 3: 내장 QR (더 간단한 설정)"""
    ESC = b'\x1b'
    GS = b'\x1d'
    commands = []
    commands.append(ESC + b'@')
    commands.append("\n================================\n".encode('euc-kr'))
    commands.append("     *** 방법 3 ***\n".encode('euc-kr'))
    commands.append("  내장 QR 간단 설정\n".encode('euc-kr'))
    commands.append("================================\n\n".encode('euc-kr'))

    qr_data = TEST_URL.encode('utf-8')
    data_len = len(qr_data) + 3

    # Model 2
    commands.append(GS + b'(k' + bytes([3, 0, 49, 65, 50]))
    # Error correction L
    commands.append(GS + b'(k' + bytes([3, 0, 49, 69, 48]))
    # Size 4
    commands.append(GS + b'(k' + bytes([3, 0, 49, 67, 4]))
    # Store data
    commands.append(GS + b'(k' + bytes([data_len & 0xFF, (data_len >> 8) & 0xFF, 49, 80, 48]) + qr_data)
    # Print
    commands.append(GS + b'(k' + bytes([3, 0, 49, 81, 48]))

    commands.append(f"\n\nURL: {TEST_URL}\n\n\n".encode('euc-kr'))
    commands.append(GS + b'V' + bytes([1]))
    return b''.join(commands)


def method_4_native_qr_model1():
    """방법 4: 내장 QR Model 1 (구형)"""
    ESC = b'\x1b'
    GS = b'\x1d'
    commands = []
    commands.append(ESC + b'@')
    commands.append("\n================================\n".encode('euc-kr'))
    commands.append("     *** 방법 4 ***\n".encode('euc-kr'))
    commands.append("  내장 QR Model 1\n".encode('euc-kr'))
    commands.append("================================\n\n".encode('euc-kr'))

    qr_data = TEST_URL.encode('utf-8')
    data_len = len(qr_data) + 3

    # Model 1 (n=49)
    commands.append(GS + b'(k' + bytes([3, 0, 49, 65, 49]))
    # Error correction L
    commands.append(GS + b'(k' + bytes([3, 0, 49, 69, 48]))
    # Size 4
    commands.append(GS + b'(k' + bytes([3, 0, 49, 67, 4]))
    # Store data
    commands.append(GS + b'(k' + bytes([data_len & 0xFF, (data_len >> 8) & 0xFF, 49, 80, 48]) + qr_data)
    # Print
    commands.append(GS + b'(k' + bytes([3, 0, 49, 81, 48]))

    commands.append(f"\n\nURL: {TEST_URL}\n\n\n".encode('euc-kr'))
    commands.append(GS + b'V' + bytes([1]))
    return b''.join(commands)


def method_5_raster_tiny():
    """방법 5: Raster 초소형 (40x40)"""
    ESC = b'\x1b'
    GS = b'\x1d'
    commands = []
    commands.append(ESC + b'@')
    commands.append("\n================================\n".encode('euc-kr'))
    commands.append("     *** 방법 5 ***\n".encode('euc-kr'))
    commands.append("  Raster 40x40 (GS v 0)\n".encode('euc-kr'))
    commands.append("================================\n\n".encode('euc-kr'))

    # 40x40 QR
    qr = qrcode.QRCode(version=1, box_size=1, border=1)
    qr.add_data(TEST_URL)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white").resize((40, 40)).convert('1')
    width, height = img.size
    pixels = img.load()

    width_bytes = (width + 7) // 8
    commands.append(GS + b'v0' + bytes([0]))
    commands.append(bytes([width_bytes & 0xFF, (width_bytes >> 8) & 0xFF]))
    commands.append(bytes([height & 0xFF, (height >> 8) & 0xFF]))

    for y in range(height):
        for x in range(0, width, 8):
            byte = 0
            for bit in range(8):
                if x + bit < width and pixels[x + bit, y] == 0:
                    byte |= (1 << (7 - bit))
            commands.append(bytes([byte]))

    commands.append(f"\n\nURL: {TEST_URL}\n\n\n".encode('euc-kr'))
    commands.append(GS + b'V' + bytes([1]))
    return b''.join(commands)


def method_6_no_align():
    """방법 6: 정렬 없이 + 작은 QR"""
    ESC = b'\x1b'
    GS = b'\x1d'
    commands = []
    commands.append(ESC + b'@')
    # 정렬 명령 없음!
    commands.append("\n================================\n".encode('euc-kr'))
    commands.append("     *** 방법 6 ***\n".encode('euc-kr'))
    commands.append("  정렬 없음 + QR 35x35\n".encode('euc-kr'))
    commands.append("================================\n\n".encode('euc-kr'))

    # 35x35 QR
    qr = qrcode.QRCode(version=1, box_size=1, border=1)
    qr.add_data(TEST_URL)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white").resize((35, 35)).convert('1')
    width, height = img.size
    pixels = img.load()

    # ESC * m=1 (8-dot double-density)
    for y in range(0, height, 8):
        commands.append(ESC + b'*' + bytes([1, width & 0xFF, (width >> 8) & 0xFF]))
        for x in range(width):
            byte = 0
            for bit in range(min(8, height - y)):
                if pixels[x, y + bit] == 0:
                    byte |= (1 << (7 - bit))
            commands.append(bytes([byte]))
        commands.append(b'\n')

    commands.append(f"\nURL: {TEST_URL}\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 테스트 v2 - 더 많은 변형")
    print("="*60)
    print(f"프린터: {PRINTER_IP}:{PRINTER_PORT}")
    print(f"테스트 URL: {TEST_URL}")
    print("="*60)

    methods = [
        ("방법 1: 30x30 ESC * m=0", method_1_tiny_qr_escstar),
        ("방법 2: 50x50 ESC * m=32", method_2_medium_qr_escstar_mode32),
        ("방법 3: 내장 QR 간단", method_3_native_qr_simple),
        ("방법 4: 내장 QR Model 1", method_4_native_qr_model1),
        ("방법 5: 40x40 Raster", method_5_raster_tiny),
        ("방법 6: 정렬 없음 35x35", method_6_no_align),
    ]

    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:
        print(f"{name}: {'✅' if success else '❌'}")

    print("\n6장의 영수증이 나옵니다. QR이 보이는 번호를 알려주세요!")
    print("="*60)


if __name__ == "__main__":
    main()
