import base64
import pyperclip
import win32clipboard
from io import BytesIO
from PIL import Image, ImageGrab, ImageFont, ImageDraw
import requests
import numpy as np
import cv2
import time
import os, sys
from datetime import datetime
import random
import pywinauto
import io
import logging

class ClipboardImageManager:
    def __init__(self, logger, watermark_font_size=36, debug_flag=False):
        self.logger = logger
        self.debug = debug_flag  # 디버그 플래그를 클래스 변수로 사용

        # 프로그램이 위치한 경로 기준으로 폰트 경로 설정
        self.base_path = self.get_base_dir()
        # 먼저 현재 모듈과 같은 디렉토리에서 폰트 파일 찾기
        current_dir = os.path.dirname(os.path.abspath(__file__))
        self.font_path = os.path.join(current_dir, 'HakgyoansimDunggeunmisoTTFB.ttf')
        
        # 폰트 파일이 없으면 다른 경로들을 시도
        if not os.path.exists(self.font_path):
            alternative_paths = [
                os.path.join(self.base_path, 'HakgyoansimDunggeunmisoTTFB.ttf'),
                os.path.join(self.base_path, 'src', 'modules', 'HakgyoansimDunggeunmisoTTFB.ttf'),
                os.path.join(os.path.dirname(self.base_path), 'src', 'modules', 'HakgyoansimDunggeunmisoTTFB.ttf')
            ]
            
            for alt_path in alternative_paths:
                if os.path.exists(alt_path):
                    self.font_path = alt_path
                    break

        # 폰트 로드 (예외 처리 추가)
        try:
            self.font = ImageFont.truetype(self.font_path, watermark_font_size)
            self.logger.log(f"폰트 로드 성공: {self.font_path}", level=logging.DEBUG)
        except Exception as e:
            self.logger.log(f"커스텀 폰트 로드 실패 ({self.font_path}): {e}", level=logging.WARNING)
            try:
                # 기본 폰트 사용
                self.font = ImageFont.load_default()
                self.logger.log("기본 폰트를 사용합니다.", level=logging.INFO)
            except Exception as e2:
                self.logger.log(f"기본 폰트 로드도 실패: {e2}", level=logging.ERROR)
                # 최후의 수단으로 None 설정
                self.font = None

        # self.debug = True

    def reset_state(self):
        """클립보드 이미지 관리자의 상태를 초기화합니다."""
        self.logger.log("ClipboardImageManager 상태 초기화", level=logging.DEBUG)
        # 클립보드 비우기
        self.clear_clipboard()

    def get_base_dir(self):
        """
        실행 환경에 따라 base_dir을 설정하는 메서드.
        cx_Freeze로 패키징된 경우 실행 파일의 경로, 일반 Python 환경일 경우 __file__을 기준으로 설정.
        """
        if getattr(sys, 'frozen', False):  # 패키징된 경우
            base_dir = os.path.dirname(sys.executable)
            internal_dir = os.path.join(base_dir, 'lib', 'src')  # lib 디렉토리 포함
            if os.path.exists(internal_dir):  # lib 디렉토리가 존재하면 base_dir로 설정
                return internal_dir

        else:  # 일반 Python 실행 환경
            base_dir = os.path.dirname(os.path.abspath(__file__))
            debug_dir = os.path.join(base_dir, 'src')  # lib 디렉토리 포함

        return debug_dir


    def get_clipboard_data(self):
        """클립보드의 텍스트 또는 이미지 데이터를 가져옵니다."""
        self.logger.log("클립보드의 텍스트 또는 이미지 데이터를 가져옵니다", level=logging.DEBUG)
        
        max_attempts = 5
        attempt = 0
        
        while attempt < max_attempts:
            try:
                # 1. 텍스트 데이터 우선 시도
                clipboard_text = pyperclip.paste()
                if clipboard_text:
                    return clipboard_text
                
                # 2. 텍스트가 없으면 이미지 확인
                self.logger.log("텍스트 데이터가 없어 이미지 데이터 확인 시도", level=logging.DEBUG)
                image = ImageGrab.grabclipboard()
                if isinstance(image, Image.Image):  # 이미지 데이터가 있는 경우
                    self.logger.log("클립보드에 이미지 데이터가 확인되었습니다.", level=logging.DEBUG)
                    return image  # PIL 이미지 객체 반환
                else:
                    self.logger.log("클립보드에 텍스트 또는 이미지 데이터가 없습니다.", level=logging.DEBUG)
                    return None
                    
            except Exception as e:
                attempt += 1
                self.logger.log(f"클립보드 데이터를 가져오는 중 오류 발생 (시도 {attempt}/{max_attempts}): {e}", level=logging.WARNING)
                if attempt < max_attempts:
                    time.sleep(0.5)  # 0.5초 대기 후 재시도
                else:
                    self.logger.log(f"클립보드 데이터를 가져오는 중 최대 시도 횟수 초과: {e}", level=logging.ERROR, exc_info=True)
                    return None

    def set_image_to_clipboard(self, image):
        """이미지를 클립보드에 넣는 함수 (Windows 전용)"""
        output = BytesIO()
        image.save(output, "BMP")
        self.logger.log(f"이미지 데이터 BMP 변환", level=logging.DEBUG)

        data = output.getvalue()[14:]  # BMP 헤더 제거
        output.close()
        self.logger.log(f"이미지 BMP 헤더 제거", level=logging.DEBUG)

        # 클립보드 접근 재시도 로직
        max_attempts = 5
        attempt = 0
        success = False

        while attempt < max_attempts and not success:
            try:
                # 클립보드에 이미지 데이터 넣기
                win32clipboard.OpenClipboard()
                win32clipboard.EmptyClipboard()
                win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
                win32clipboard.CloseClipboard()
                success = True
                self.logger.log(f"클립보드 데이터 저장 성공 (시도 {attempt+1}/{max_attempts})", level=logging.DEBUG)
            except Exception as e:
                attempt += 1
                self.logger.log(f"클립보드 데이터 저장 실패 (시도 {attempt}/{max_attempts}): {e}", level=logging.WARNING)
                if attempt < max_attempts:
                    time.sleep(0.5)  # 0.5초 대기 후 재시도
        
        # 클립보드가 제대로 설정되었는지 확인하는 로그
        if success:
            try:
                time.sleep(0.1)  # 아주 짧은 대기 시간
                win32clipboard.OpenClipboard()
                if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB):
                    self.logger.log("클립보드 데이터 확인 성공", level=logging.DEBUG)
                else:
                    self.logger.log("클립보드 데이터 확인 실패", level=logging.ERROR)
                win32clipboard.CloseClipboard()
            except Exception as e:
                self.logger.log(f"클립보드 데이터 확인 중 오류: {e}", level=logging.ERROR)
                
    def save_image_to_path(self, image, path):
        try:
            if image:
                # 이미지를 저장 경로에 저장
                self.logger.log(f"이미지 저장 완료 : {path}", level=logging.INFO)
                image.save(path, format='PNG')
                return path
            
        except Exception as e:
            raise RuntimeError(f"이미지 저장 중 오류 발생: {e}")

    def add_watermark(self, image, watermark_text="Watermark", opacity_percent=30, angle=30, font_size=36):
        """
        이미지에 텍스트 워터마크를 이미지 전체에 걸쳐서 추가하는 함수
        :param image: PIL 이미지 객체
        :param watermark_text: 워터마크로 추가할 텍스트
        :param opacity_percent: 워터마크의 투명도 (0~100)
        :param angle: 워터마크 텍스트 회전 각도 (기본 30도)
        :param font_size: 워터마크 텍스트의 폰트 크기 (기본 36)
        :return: 워터마크가 추가된 이미지
        """
        # 폰트가 로드되지 않은 경우 원본 이미지 반환
        if self.font is None:
            self.logger.log("폰트가 로드되지 않아 워터마크를 추가할 수 없습니다. 원본 이미지를 반환합니다.", level=logging.WARNING)
            return image
            
        # 이미지 복사본 생성
        watermark_image = image.copy()
        
        # 폰트 설정 (안전한 폰트 로딩)
        try:
            # self.font가 있으면 크기만 조정해서 새 폰트 생성
            if hasattr(self, 'font_path') and os.path.exists(self.font_path):
                font = ImageFont.truetype(self.font_path, font_size)
            else:
                # 크기를 조정할 수 없으면 기존 폰트 사용
                font = self.font
        except Exception as e:
            self.logger.log(f"폰트 크기 조정 실패: {e}. 기본 폰트를 사용합니다.", level=logging.WARNING)
            font = self.font

        # 텍스트 투명도를 0~255로 변환
        opacity = int(255 * (opacity_percent / 100))

        # 텍스트 크기 측정 (textbbox 사용)
        draw = ImageDraw.Draw(watermark_image)
        bbox = draw.textbbox((0, 0), watermark_text, font=font)
        text_width, text_height = bbox[2] - bbox[0], bbox[3] - bbox[1]

        # 이미지 크기
        width, height = image.size

        # 워터마크 레이어 생성
        watermark_layer = Image.new("RGBA", (width, height))  # RGBA 이미지 생성

        # 지그재그 간격 설정
        zigzag_step = int(text_height * 2)  # Y축의 지그재그 간격


        # 이미지 전체에 반복적으로 워터마크 텍스트 그리기 (지그재그 형태)
        for y in range(0, height, zigzag_step):
            for x in range(0, width, int(text_width * 3)):  # 3배 너비 간격으로 반복
                # 텍스트가 한 줄씩 지그재그 형태로 X축을 교차하여 이동
                x_offset = (y // zigzag_step) % 2 * int(text_width * 1.5)  # 짝수 행에서는 X축을 약간 이동

                # 텍스트 레이어 생성
                text_layer = Image.new("RGBA", (text_width, text_height), (255, 255, 255, 0))
                text_draw = ImageDraw.Draw(text_layer)
                
                # 텍스트 그리기
                text_draw.text((0, 0), watermark_text, fill=(255, 255, 255, opacity), font=font)
                
                # 텍스트 회전
                rotated_text_layer = text_layer.rotate(angle, expand=1)
                
                # 회전된 텍스트를 워터마크 레이어에 추가
                watermark_layer.paste(rotated_text_layer, (x + x_offset, y), rotated_text_layer)

        # 원본 이미지와 워터마크 레이어 합성
        watermark_image = Image.alpha_composite(watermark_image.convert("RGBA"), watermark_layer)
        
        # 최종적으로 RGB 형식으로 변환 후 반환
        return watermark_image.convert("RGB")

    def base64_to_image(self, base64_data):
        """Base64 데이터를 이미지로 변환하는 함수"""
        if base64_data.startswith('data:image'):
            header, encoded = base64_data.split(',', 1)
            img_data = base64.b64decode(encoded)
            image = Image.open(BytesIO(img_data))
            return image
        else:
            self.logger.log("유효하지 않은 Base64 이미지 데이터입니다.", level=logging.DEBUG)
            return None

    def image_to_base64(self, image):
        # 이미지 Base64로 변환
        buffer = io.BytesIO()
        image.save(buffer, format="PNG")
        base64_image = base64.b64encode(buffer.getvalue()).decode('utf-8')
        return base64_image

    def download_image_from_url(self, url, max_retries=3):
        """URL에서 이미지를 다운로드하고 PIL 이미지 객체로 반환"""
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "Accept-Language": "en-US,en;q=0.9",
            "Accept-Encoding": "gzip, deflate, br",
            "DNT": "1",  # Do Not Track 요청 헤더
            "Connection": "keep-alive",
            "Upgrade-Insecure-Requests": "1",
            "Cache-Control": "max-age=0"
        }

        retries = 0
        while retries < max_retries:
            try:
                self.logger.log(f"이미지 URL 다운로드 중: {url}", level=logging.DEBUG)
                response = requests.get(url, headers=headers, stream=True)
                
                # 상태 코드가 200이 아니면 재시도
                if response.status_code == 200:
                    # OpenCV로 이미지를 로드하여 변환
                    image = np.asarray(bytearray(response.content), dtype="uint8")
                    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
                    
                    # OpenCV에서 이미지를 PIL로 변환
                    if image is not None:
                        pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
                        return pil_image
                    else:
                        self.logger.log(f"이미지 파일 형식이 올바르지 않습니다. 대상 URL: {url}", level=logging.DEBUG)
                        return None
                else:
                    self.logger.log(f"이미지 로딩 실패, HTTP 상태 코드: {response.status_code}. 재시도 {retries + 1}/{max_retries}", level=logging.DEBUG)
                    retries += 1
                    # await asyncio.sleep(random.randint(2, 5))  # 2~5초 대기 후 재시도
                    time.sleep(random.randint(2, 5))

            except Exception as e:
                self.logger.log(f"이미지 로딩 중 오류 발생: {e}. 재시도 {retries + 1}/{max_retries}", level=logging.DEBUG)
                retries += 1
                # await asyncio.sleep(random.randint(2, 5))  # 예외 발생 시 대기 후 재시도
                time.sleep(random.randint(2, 5))

        self.logger.log("이미지 다운로드 최대 재시도 횟수를 초과했습니다.", level=logging.DEBUG)
        return None

    def process_clipboard(self, original_url, is_success_translated, toggle_states, path=None, is_thumb=False):
        """클립보드의 내용을 처리하고, 필요한 경우 이미지 변환, 크롭 또는 클립보드 비우기"""

        try:
            is_watermark = toggle_states.get('watermark')
            self.logger.log(f"is_watermark : {is_watermark}", level=logging.DEBUG)

            watermark_text = toggle_states.get('watermark_text')
            self.logger.log(f"watermark_text : {watermark_text}", level=logging.DEBUG)

            opacity_percent = toggle_states.get('opacity_percent')
            self.logger.log(f"opacity_percent : {opacity_percent}", level=logging.DEBUG)

            clipboard_data = self.get_clipboard_data()

            self.logger.log("clipboard_data", level=logging.DEBUG)
            self.logger.log(f"{clipboard_data}", level=logging.DEBUG)
            self.logger.log(f"============================", level=logging.DEBUG)

            # 1. 클립보드의 데이터가 Base64 이미지일 경우
            if isinstance(clipboard_data, str) and clipboard_data.startswith('data:image'):
                self.logger.log("[process_clipboard] data:image 감지 : 이미지 데이터로 변환", level=logging.INFO)
                image = self.base64_to_image(clipboard_data)
                if image:
                    width, _ = image.size
                    self.logger.log(f"Base64 이미지 크기: {width}px", level=logging.DEBUG)
                    
                    # 가로 크기가 200픽셀 이상이면 크롭
                    if width >= 200:
                        self.logger.log("이미지 가로 크기 200픽셀 이상: 크롭 진행 중...", level=logging.DEBUG)
                        cropped_image = self.crop_image(image, is_thumb)  # 크롭 메서드 사용

                        # 워터마크 추가
                        if is_watermark and not is_thumb:  # is_thumb가 True라면 워터마크 추가를 건너뜁니다
                            self.logger.log("워터마크 추가 중...", level=logging.DEBUG)
                            cropped_watermark_image = self.add_watermark(cropped_image, watermark_text, opacity_percent)  # 워터마크 추가
                            cropped_image = cropped_watermark_image

                        self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장
                        if path:
                            self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                            self.save_image_to_path(cropped_image, path)
                    else:
                        self.logger.log("이미지 가로 크기 200픽셀 이하: 클립보드 비움.", level=logging.DEBUG)
                        self.clear_clipboard()
                else:
                    self.logger.log("Base64 이미지 변환 실패.", level=logging.DEBUG)

            # 2. 클립보드에 이미지가 있을 경우
            elif isinstance(clipboard_data, Image.Image):
                self.logger.log("[process_clipboard] 클립보드 이미지 확인", level=logging.INFO)

                image = clipboard_data
                width, _ = image.size
                self.logger.log(f"클립보드에 있는 이미지 크기: {width}px", level=logging.DEBUG)

                if width >= 200:
                    self.logger.log("이미지 가로 크기 200픽셀 이상: 크롭 진행 중...", level=logging.DEBUG)
                    cropped_image = self.crop_image(image, is_thumb)  # 크롭 메서드 사용

                    # 워터마크 추가
                    if is_watermark and not is_thumb:  # is_thumb가 True라면 워터마크 추가를 건너뜁니다
                        self.logger.log("워터마크 추가 중...", level=logging.DEBUG)
                        cropped_watermark_image = self.add_watermark(cropped_image, watermark_text, opacity_percent)  # 워터마크 추가
                        cropped_image = cropped_watermark_image

                    self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장
                    if path:
                        self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                        self.save_image_to_path(cropped_image, path)

                else:
                    self.logger.log("이미지 가로 크기 200픽셀 이하: 클립보드 비움.", level=logging.DEBUG)
                    self.clear_clipboard()

            # 3. 클립보드에 데이터가 없거나 html > whale-ocr 처리
            elif clipboard_data == "html > whale-ocr" or clipboard_data is None or not is_success_translated:
                if clipboard_data == "html > whale-ocr":
                    self.logger.log("[process_clipboard] html > whale-ocr 감지 : 이미지 번역 실패 확인", level=logging.INFO)
                elif clipboard_data is None:
                    self.logger.log("[process_clipboard] 클립보드에 이미지 없음", level=logging.INFO)
                elif is_success_translated is None:
                    self.logger.log("[process_clipboard] 번역 실패로 인한 원본이미지 다운로드", level=logging.INFO)

                if original_url:
                    image = self.download_image_from_url(original_url)
                    if image:
                        self.logger.log("원본 이미지 다운로드 성공!", level=logging.DEBUG)

                        self.set_image_to_clipboard(image)  # 크롭 없이 저장
                        if path:
                            self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                            self.save_image_to_path(image, path)
                    else:
                        self.logger.log("원본 이미지 다운로드 실패.", level=logging.DEBUG)
                else:
                    self.logger.log("원본 이미지 URL을 찾을 수 없습니다.", level=logging.DEBUG)

        except Exception as e:
            self.logger.log(f"클립보드에서 이미지를 처리하는 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)


    def process_clipboard_to_save_path(self, original_url, is_success_translated, toggle_states, path=None, is_thumb=False):
        """클립보드의 내용을 처리하고, 필요한 경우 이미지 변환, 크롭 또는 클립보드 비우기"""

        try:
            is_watermark = toggle_states.get('watermark')
            self.logger.log(f"is_watermark : {is_watermark}", level=logging.DEBUG)

            watermark_text = toggle_states.get('watermark_text')
            self.logger.log(f"watermark_text : {watermark_text}", level=logging.DEBUG)

            opacity_percent = toggle_states.get('opacity_percent')
            self.logger.log(f"opacity_percent : {opacity_percent}", level=logging.DEBUG)

            clipboard_data = self.get_clipboard_data()

            self.logger.log("clipboard_data", level=logging.DEBUG)
            self.logger.log(f"{clipboard_data}", level=logging.DEBUG)
            self.logger.log(f"============================", level=logging.DEBUG)

            # 1. 클립보드의 데이터가 Base64 이미지일 경우
            if isinstance(clipboard_data, str) and clipboard_data.startswith('data:image'):
                self.logger.log("[process_clipboard] data:image 감지 : 이미지 데이터로 변환", level=logging.INFO)
                image = self.base64_to_image(clipboard_data)
                if image:
                    width, _ = image.size
                    self.logger.log(f"Base64 이미지 크기: {width}px", level=logging.DEBUG)
                    
                    # 가로 크기가 200픽셀 이상이면 크롭
                    if width >= 200:
                        self.logger.log("이미지 가로 크기 200픽셀 이상: 크롭 진행 중...", level=logging.DEBUG)
                        cropped_image = self.crop_image(image, is_thumb)  # 크롭 메서드 사용

                        # 워터마크 추가
                        if is_watermark and not is_thumb:  # is_thumb가 True라면 워터마크 추가를 건너뜁니다
                            self.logger.log("워터마크 추가 중...", level=logging.DEBUG)
                            cropped_watermark_image = self.add_watermark(cropped_image, watermark_text, opacity_percent)  # 워터마크 추가
                            cropped_image = cropped_watermark_image

                        if path:
                            self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                            return self.save_image_to_path(cropped_image, path)
                        else:
                            self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장

                    else:
                        self.logger.log("이미지 가로 크기 200픽셀 이하로 처리불가: 클립보드 비움.", level=logging.DEBUG)
                        self.clear_clipboard()
                else:
                    self.logger.log("Base64 이미지 변환 실패.", level=logging.DEBUG)

            # 2. 클립보드에 이미지가 있을 경우
            elif isinstance(clipboard_data, Image.Image):
                self.logger.log("[process_clipboard] 클립보드 이미지 확인", level=logging.INFO)

                image = clipboard_data
                width, _ = image.size
                self.logger.log(f"클립보드에 있는 이미지 크기: {width}px", level=logging.DEBUG)

                if width >= 200:
                    self.logger.log("이미지 가로 크기 200픽셀 이상: 크롭 진행 중...", level=logging.DEBUG)
                    cropped_image = self.crop_image(image, is_thumb)  # 크롭 메서드 사용

                    # 워터마크 추가
                    if is_watermark and not is_thumb:  # is_thumb가 True라면 워터마크 추가를 건너뜁니다
                        self.logger.log("워터마크 추가 중...", level=logging.DEBUG)
                        cropped_watermark_image = self.add_watermark(cropped_image, watermark_text, opacity_percent)  # 워터마크 추가
                        cropped_image = cropped_watermark_image

                    if path:
                        self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                        return self.save_image_to_path(cropped_image, path)
                    else:
                        self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장

                else:
                    self.logger.log("이미지 가로 크기 200픽셀 이하로 처리불가: 클립보드 비움.", level=logging.DEBUG)
                    self.clear_clipboard()

            # 3. 클립보드에 데이터가 없거나 html > whale-ocr 처리
            elif clipboard_data == "html > whale-ocr" or clipboard_data is None or not is_success_translated or clipboard_data.startswith("https://") or clipboard_data.startswith("http://"):
                if clipboard_data == "html > whale-ocr":
                    self.logger.log("[process_clipboard] html > whale-ocr 감지 : 이미지 번역 실패 확인", level=logging.INFO)
                elif clipboard_data is None:
                    self.logger.log("[process_clipboard] 클립보드에 이미지 없음", level=logging.INFO)
                elif is_success_translated is None:
                    self.logger.log("[process_clipboard] 번역 실패로 인한 원본이미지 다운로드", level=logging.INFO)
                elif clipboard_data.startswith("https://") or clipboard_data.startswith("http://"):
                    self.logger.log("[process_clipboard] 타임아웃으로 인한 번역 실패 - 원본이미지 다운로드", level=logging.INFO)

                if original_url:
                    image = self.download_image_from_url(original_url)
                    if image:
                        self.logger.log("원본 이미지 다운로드 성공!", level=logging.DEBUG)

                        if path:
                            self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                            return self.save_image_to_path(image, path)
                        else:
                            self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장
                    else:
                        self.logger.log("원본 이미지 다운로드 실패.", level=logging.DEBUG)
                else:
                    self.logger.log("원본 이미지 URL을 찾을 수 없습니다.", level=logging.DEBUG)

        except Exception as e:
            self.logger.log(f"클립보드에서 이미지를 처리하는 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)

    def process_clipboard_to_save_path_with_local_hosted_image(self, local_image_path, is_success_translated, toggle_states, path=None, is_thumb=False):
        """클립보드의 내용을 처리하고, 필요한 경우 이미지 변환, 크롭 또는 클립보드 비우기
        
        Returns:
            str: 처리된 이미지 파일 경로 (성공 시)
            str: 원본 이미지 파일 경로 (실패 시)
        """
        
        # 매개변수 유효성 검사
        if not local_image_path or not os.path.exists(local_image_path):
            self.logger.log(f"유효하지 않은 로컬 이미지 경로: {local_image_path}", level=logging.ERROR)
            return local_image_path if local_image_path else None
            
        if not toggle_states:
            self.logger.log("toggle_states가 제공되지 않았습니다", level=logging.WARNING)
            toggle_states = {}

        try:
            is_watermark = toggle_states.get('watermark', False)
            self.logger.log(f"is_watermark : {is_watermark}", level=logging.DEBUG)

            watermark_text = toggle_states.get('watermark_text', '')
            self.logger.log(f"watermark_text : {watermark_text}", level=logging.DEBUG)

            opacity_percent = toggle_states.get('opacity_percent', 20)
            self.logger.log(f"opacity_percent : {opacity_percent}", level=logging.DEBUG)

            clipboard_data = self.get_clipboard_data()

            self.logger.log(f"type(clipboard_data) : {type(clipboard_data)}", level=logging.DEBUG)
            self.logger.log(f"============================", level=logging.DEBUG)

            # 1. 클립보드의 데이터가 Base64 이미지일 경우
            if isinstance(clipboard_data, str) and clipboard_data.startswith('data:image'):
                self.logger.log("[process_clipboard] data:image 감지 : 이미지 데이터로 변환", level=logging.INFO)
                image = self.base64_to_image(clipboard_data)
                if image:
                    width, _ = image.size
                    self.logger.log(f"Base64 이미지 크기: {width}px", level=logging.DEBUG)
                    
                    # 가로 크기가 200픽셀 이상이면 크롭
                    if width >= 200:
                        self.logger.log("이미지 가로 크기 200픽셀 이상: 크롭 진행 중...", level=logging.DEBUG)
                        cropped_image = self.crop_image(image, is_thumb)  # 크롭 메서드 사용

                        # 워터마크 추가
                        if is_watermark and not is_thumb:  # is_thumb가 True라면 워터마크 추가를 건너뜁니다
                            self.logger.log("워터마크 추가 중...", level=logging.DEBUG)
                            cropped_watermark_image = self.add_watermark(cropped_image, watermark_text, opacity_percent)  # 워터마크 추가
                            cropped_image = cropped_watermark_image

                        if path:
                            self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                            saved_path = self.save_image_to_path(cropped_image, path)
                            return saved_path if saved_path else local_image_path
                        else:
                            self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장
                            return local_image_path  # path가 없으면 원본 경로 반환

                    else:
                        self.logger.log("이미지 가로 크기 200픽셀 이하로 처리불가: 클립보드 비움.", level=logging.DEBUG)
                        self.clear_clipboard()
                        return local_image_path
                else:
                    self.logger.log("Base64 이미지 변환 실패.", level=logging.DEBUG)
                    return local_image_path

            # 2. 클립보드에 이미지가 있을 경우
            elif isinstance(clipboard_data, Image.Image):
                self.logger.log("[process_clipboard] 클립보드 이미지 확인", level=logging.INFO)

                image = clipboard_data
                width, _ = image.size
                self.logger.log(f"클립보드에 있는 이미지 크기: {width}px", level=logging.DEBUG)

                if width >= 200:
                    self.logger.log("이미지 가로 크기 200픽셀 이상: 크롭 진행 중...", level=logging.DEBUG)
                    cropped_image = self.crop_image(image, is_thumb)  # 크롭 메서드 사용

                    # 워터마크 추가
                    if is_watermark and not is_thumb:  # is_thumb가 True라면 워터마크 추가를 건너뜁니다
                        self.logger.log("워터마크 추가 중...", level=logging.DEBUG)
                        cropped_watermark_image = self.add_watermark(cropped_image, watermark_text, opacity_percent)  # 워터마크 추가
                        cropped_image = cropped_watermark_image

                    if path:
                        self.logger.log("이미지 저장 시도...", level=logging.DEBUG)
                        saved_path = self.save_image_to_path(cropped_image, path)
                        return saved_path if saved_path else local_image_path
                    else:
                        self.set_image_to_clipboard(cropped_image)  # 클립보드에 저장
                        return local_image_path  # path가 없으면 원본 경로 반환

                else:
                    self.logger.log("이미지 가로 크기 200픽셀 이하로 처리불가: 클립보드 비움.", level=logging.DEBUG)
                    self.clear_clipboard()
                    return local_image_path

            # 3. 클립보드에 데이터가 없거나 html > whale-ocr 처리
            elif clipboard_data == "html > whale-ocr" or clipboard_data is None or not is_success_translated or clipboard_data.startswith("https://") or clipboard_data.startswith("http://"):
                if clipboard_data == "html > whale-ocr":
                    self.logger.log("[process_clipboard] html > whale-ocr 감지 : 이미지 번역 실패 확인", level=logging.INFO)
                elif clipboard_data is None:
                    self.logger.log("[process_clipboard] 클립보드에 이미지 없음", level=logging.INFO)
                elif not is_success_translated:
                    self.logger.log("[process_clipboard] 번역 실패로 인한 원본이미지 사용", level=logging.INFO)
                elif clipboard_data.startswith("https://") or clipboard_data.startswith("http://"):
                    self.logger.log("[process_clipboard] 타임아웃으로 인한 번역 실패 - 원본이미지 사용", level=logging.INFO)

                return local_image_path
            
            # 4. 기타 예상하지 못한 클립보드 데이터
            else:
                self.logger.log(f"[process_clipboard] 예상하지 못한 클립보드 데이터 타입: {type(clipboard_data)}", level=logging.WARNING)
                return local_image_path

        except Exception as e:
            self.logger.log(f"클립보드에서 이미지를 처리하는 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
            return local_image_path  # 오류 시 원본 경로 반환

    def is_clipboard_image(self):
        """클립보드에 이미지가 있는지 확인하는 함수"""
        max_attempts = 5
        attempt = 0
        
        while attempt < max_attempts:
            try:
                win32clipboard.OpenClipboard()
                is_clipboard_image_flag = win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB)
                win32clipboard.CloseClipboard()
                
                if is_clipboard_image_flag:
                    self.logger.log("클립보드에 이미지가 존재합니다.", level=logging.DEBUG)
                else:
                    self.logger.log("클립보드에 이미지가 없습니다.", level=logging.DEBUG)
                
                return is_clipboard_image_flag
                
            except Exception as e:
                attempt += 1
                # 클립보드가 열려있으면 닫기 시도
                try:
                    win32clipboard.CloseClipboard()
                except:
                    pass
                
                self.logger.log(f"클립보드 이미지 확인 중 오류 발생 (시도 {attempt}/{max_attempts}): {e}", level=logging.WARNING)
                if attempt < max_attempts:
                    time.sleep(0.5)  # 0.5초 대기 후 재시도
                else:
                    self.logger.log(f"클립보드 이미지 확인 중 최대 시도 횟수 초과: {e}", level=logging.ERROR, exc_info=True)
                    return False

    def get_image_from_clipboard(self):
        """클립보드에서 이미지를 가져오는 함수"""
        max_attempts = 5
        attempt = 0
        
        while attempt < max_attempts:
            try:
                win32clipboard.OpenClipboard()
                if self.is_clipboard_image():
                    dib_data = win32clipboard.GetClipboardData(win32clipboard.CF_DIB)
                    win32clipboard.CloseClipboard()
                    image = Image.open(BytesIO(dib_data))
                    return image
                else:
                    win32clipboard.CloseClipboard()
                    self.logger.log("클립보드에 이미지가 없습니다.", level=logging.DEBUG)
                    return None
            except Exception as e:
                attempt += 1
                # 클립보드가 열려있으면 닫기 시도
                try:
                    win32clipboard.CloseClipboard()
                except:
                    pass
                
                self.logger.log(f"클립보드에서 이미지를 가져오는 중 오류 발생 (시도 {attempt}/{max_attempts}): {e}", level=logging.WARNING)
                if attempt < max_attempts:
                    time.sleep(0.5)  # 0.5초 대기 후 재시도
                else:
                    self.logger.log(f"클립보드에서 이미지를 가져오는 중 최대 시도 횟수 초과: {e}", level=logging.ERROR, exc_info=True)
                    return None

    def clear_clipboard(self):
        """클립보드를 비우는 함수"""
        max_attempts = 5
        attempt = 0
        success = False

        while attempt < max_attempts and not success:
            try:
                # 먼저 pywinauto로 시도
                try:
                    pywinauto.clipboard.EmptyClipboard()
                    success = True
                except:
                    # pywinauto 실패 시 win32clipboard로 시도
                    win32clipboard.OpenClipboard()
                    win32clipboard.EmptyClipboard()
                    win32clipboard.CloseClipboard()
                    success = True

                self.logger.log(f"클립보드가 비워졌습니다. (시도 {attempt+1}/{max_attempts})", level=logging.DEBUG)
            except Exception as e:
                attempt += 1
                self.logger.log(f"클립보드를 비우는 중 오류 발생 (시도 {attempt}/{max_attempts}): {e}", level=logging.WARNING)
                if attempt < max_attempts:
                    time.sleep(0.5)  # 0.5초 대기 후 재시도
        
        if not success:
            self.logger.log("최대 시도 횟수를 초과하여 클립보드를 비우지 못했습니다.", level=logging.ERROR)

    def crop_image(self, image, is_thumb=False, crop_percentage=0.01):
        """이미지를 주어진 퍼센트만큼 크롭하는 함수"""
        if is_thumb:
            crop_percentage = 0.03
            self.logger.log(f"썸네일 이미지 이므로 크롭 3%로 조정", level=logging.DEBUG)

        width, height = image.size
        left = width * crop_percentage
        top = height * crop_percentage
        right = width * (1 - crop_percentage)
        bottom = height * (1 - crop_percentage)

        cropped_image = image.crop((left, top, right, bottom))

        if self.debug:
            # 디버그 모드일 경우 크롭 전후 다양한 비율로 이미지 저장
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            original_image_path = os.path.join(os.getcwd(), f"original_image_{timestamp}.png")
            image.save(original_image_path)  # 크롭 전 이미지 저장
            self.logger.log(f"크롭 전 이미지 저장됨: {original_image_path}", level=logging.DEBUG)

            # 1%, 2%, 3% 크롭 이미지 저장
            crop_alternatives = [0.01, 0.02, 0.03]
            for crop in crop_alternatives:
                left_alt = width * crop
                top_alt = height * crop
                right_alt = width * (1 - crop)
                bottom_alt = height * (1 - crop)

                cropped_alt_image = image.crop((left_alt, top_alt, right_alt, bottom_alt))
                cropped_image_path = os.path.join(os.getcwd(), f"cropped_image_{int(crop*100)}_{timestamp}.png")
                cropped_alt_image.save(cropped_image_path)
                self.logger.log(f"{int(crop*100)}% 크롭된 이미지 저장됨: {cropped_image_path}", level=logging.DEBUG)

        return cropped_image