import sys
import json
import subprocess
import os
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QGridLayout,
                            QInputDialog, QFileDialog, QMessageBox, QMenu,
                            QColorDialog, QHBoxLayout, QVBoxLayout, QLabel, QFrame,
                            QShortcut, QToolButton, QDialog, QVBoxLayout, QSystemTrayIcon,
                            QApplication, QLineEdit, QListWidget, QListWidgetItem, QStyle, QButtonGroup, QRadioButton, QProgressDialog)
from PyQt5.QtCore import Qt, QSize, QMimeData, QPropertyAnimation, QRect, QEasingCurve, QTimer
from PyQt5.QtGui import QIcon, QPixmap, QColor, QKeySequence, QDrag, QCursor, QImage

class CustomButton(QToolButton):
    # ... (CustomButton 코드, 변경 없음) ...
    def __init__(self, id, parent=None):
        super().__init__(parent)
        self.id = id
        self.app_path = ""
        self.button_color = "#FFFFFF"
        self.text_color = "#000000"
        self.icon_path = ""
        self.is_folder = False
        self.is_url = False
        self.is_script = False  # 스크립트 여부 확인
        self.script_content = ""  # 스크립트 내용 저장
        self.font_size = 12
        self.base_font_size = 12 # 기준 폰트 크기
        self.shortcut = None
        self.shortcut_text = ""

        # 단축키 라벨 생성
        self.shortcut_label = QLabel(self)
        self.shortcut_label.setParent(self)
        self.shortcut_label.setStyleSheet("""
            QLabel {
                background-color: #FFE066;
                color: black;
                border: 1px solid #DEB887;
                border-radius: 3px;
                padding: 2px;
                font-size: 10px;
            }
        """)
        self.shortcut_label.hide()
        self.setMinimumSize(100, 100)
        self.clicked.connect(self.button_clicked)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.show_context_menu)
        self.setText("설정하기")
        self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        # 드래그 앤 드롭 설정
        self.setAcceptDrops(True)
        self.drag_start_position = None
        self.shortcut_label.move(self.width() - 35, 5)

        self.update_style()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        if hasattr(self, 'shortcut_label'):
            self.shortcut_label.move(self.width() - self.shortcut_label.width() - 5, 5)
            if hasattr(self, 'shortcut_text') and self.shortcut_text:
                self.shortcut_label.show()
                self.shortcut_label.raise_()

    def set_shortcut(self):
        dialog = QDialog(self)
        dialog.setWindowTitle("단축키 설정")
        dialog.setFixedSize(300, 100)

        layout = QVBoxLayout()
        label = QLabel("F1-F12 키를 직접 눌러주세요\n(F3 제외)\n단축키 제거: Delete 또는 Backspace")
        label.setAlignment(Qt.AlignCenter)
        layout.addWidget(label)
        dialog.setLayout(layout)

        def keyPressEvent(event):
            key = event.key()
            if key in (Qt.Key_Delete, Qt.Key_Backspace):
                if self.shortcut is not None:
                    self.shortcut.setEnabled(False)
                    self.shortcut.deleteLater()
                    self.shortcut = None
                    self.shortcut_text = ""
                    self.shortcut_label.hide()
                    self.update()
                    self.save_settings()
                dialog.accept()
            elif key >= Qt.Key_F1 and key <= Qt.Key_F12:
                if key == Qt.Key_F3:
                    QMessageBox.warning(dialog, "오류", "F3 키는 창 고정용으로 사용할 수 없습니다.")
                    return

                # 단축키 중복 확인
                settings = StreamDeck.load_all_settings()
                shortcut_text = QKeySequence(key).toString()

                for button_id, button_data in settings.items():
                    if isinstance(button_data, dict):  # 딕셔너리인 경우에만 확인
                        if button_data.get("shortcut") == shortcut_text and str(self.id) != button_id:
                            QMessageBox.warning(dialog, "오류", f"이미 사용 중인 단축키입니다: {shortcut_text}")
                            return

                if self.shortcut is not None:
                    self.shortcut.setEnabled(False)
                    self.shortcut.deleteLater()

                self.shortcut = QShortcut(QKeySequence(key), self)
                self.shortcut.activated.connect(self.button_clicked)
                self.shortcut_text = shortcut_text
                self.shortcut_label.setText(shortcut_text)
                self.shortcut_label.adjustSize()
                self.shortcut_label.show()
                self.update()
                self.save_settings()
                dialog.accept()

        dialog.keyPressEvent = keyPressEvent
        dialog.exec_()

    

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_start_position = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        # 버튼 위치 이동을 위한 드래그
        if not (event.buttons() & Qt.LeftButton):
            return
        if not self.drag_start_position:
            return

        # 최소 드래그 거리 확인
        if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
            return

        # 드래그 시작
        drag = QDrag(self)
        mime_data = QMimeData()
        mime_data.setText(str(self.id))
        drag.setMimeData(mime_data)

        # 드래그 시 버튼 모양 유지
        pixmap = QPixmap(self.size())
        self.render(pixmap)
        drag.setPixmap(pixmap)

        drag.exec_(Qt.MoveAction)

    def dragEnterEvent(self, event):
        # 파일 드롭과 버튼 이동 모두 처리
        if event.mimeData().hasUrls():
            event.accept()
        elif event.mimeData().hasText():
            event.acceptProposedAction()
        else:
            event.ignore()

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            file_path = event.mimeData().urls()[0].toLocalFile()

            if file_path.endswith('.app') or file_path.endswith('.app/') or os.path.isdir(file_path) or \
            file_path.endswith(('.py', '.txt', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.odt', '.ods', '.odp',
                                '.mp4', '.mov', '.avi', '.mkv', '.m4v',
                                '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.pdf', '.sh')):
                # 끝의 '/' 제거
                file_path = file_path.rstrip('/')
                self.app_path = file_path
                self.is_folder = os.path.isdir(file_path) and not file_path.endswith('.app')
                self.is_url = False

                # 파일 이름 설정
                if file_path.endswith('.app'):
                    app_name = os.path.basename(file_path).replace('.app', '')
                else:
                    app_name = os.path.basename(file_path)
                self.setText(app_name)

                # 아이콘 설정
                try:
                    if file_path.endswith('.app'):
                        # 앱 아이콘 설정
                        resources_path = os.path.join(file_path, 'Contents', 'Resources')
                        icon_candidates = [
                            'AppIcon.icns',
                            'Icon.icns',
                            'icon.icns',
                            f'{app_name}.icns',
                            'Harmony.icns',
                            'HarmonyPremium.icns',
                            f'{app_name.lower()}.icns',
                            f'{app_name.replace(" ", "")}.icns',
                            f'{app_name.split()[0]}.icns',
                            f'{app_name.split()[0]}Premium.icns'
                        ]

                        # Resources 폴더의 모든 .icns 파일 검색
                        icon_found = False
                        if os.path.exists(resources_path):
                            for file in os.listdir(resources_path):
                                if file.endswith('.icns'):
                                    if app_name.lower() in file.lower():
                                        self.icon_path = os.path.join(resources_path, file)
                                        icon_found = True
                                        break

                            # 지정된 후보에서 검색
                            if not icon_found:
                                for icon_name in icon_candidates:
                                    icon_path = os.path.join(resources_path, icon_name)
                                    if os.path.exists(icon_path):
                                        self.icon_path = icon_path
                                        break

                    elif file_path.endswith('.py'):
                        self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/PythonScriptIcon.icns"
                    elif file_path.endswith('.sh'):
                        self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ShellScriptIcon.icns"
                    elif self.is_folder:
                        if self.app_path.startswith('smb://'):
                            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericFileServerIcon.icns"
                        elif self.app_path.startswith('afp://'):
                            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AppleShareIcon.icns"
                        else:
                            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericFolderIcon.icns"
                    elif self.is_url:
                        self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericURLIcon.icns"
                    else:
                        # 기타 파일 형식에 대한 아이콘
                        if file_path.endswith(('.doc', '.docx', '.odt', '.txt', '.rtf', '.pages', '.pdf', '.xls', '.xlsx', '.ods', '.csv', '.ppt', '.pptx', '.odp', '.key')):
                            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AllMyFiles.icns"
                        elif file_path.endswith(('.mp4', '.mov', '.avi', '.mkv')):
                            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/MovieIcon.icns"
                        elif file_path.endswith(('.jpg', '.jpeg', '.png', '.gif')):
                            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ImageIcon.icns"

                except Exception as e:
                    print(f"아이콘 설정 중 오류 발생: {str(e)}")

                self.update_style()
                self.save_settings()

            event.accept()

        elif event.mimeData().hasText():
            source_id = int(event.mimeData().text())
            target_id = self.id
            parent = self.parent()
            if hasattr(parent, 'buttons'):
                parent.swap_buttons(source_id, target_id)
            event.acceptProposedAction()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls() or event.mimeData().hasText():
            event.accept()
            # 드래그 오버 시 시각적 피드백
            self.setStyleSheet(f"""
                QPushButton {{
                    background-color: {self.button_color};
                    color: {self.text_color};
                    border: 2px solid #4a9eff;
                    border-radius: 6px;
                    padding: 5px;
                    font-size: {self.font_size}px;
                    font-weight: bold;
                }}
            """)
        else:
            event.ignore()

    def dragLeaveEvent(self, event):
        # 드래그가 버튼을 벗어날 때 원래 스타일로 복구
        self.update_style()

    

    def darken_color(self, color):
        # 색상을 어둡게 만드는 함수
        color = QColor(color)
        h, s, v, a = color.getHsv()
        # 명도(v)를 20% 감소
        v = max(0, v - 50)
        color.setHsv(h, s, v, a)
        return color.name()

    def button_clicked(self):
        if self.is_script:
            try:
                if self.script_content.strip():
                    if self.is_python_script():
                        # Python 스크립트 실행
                        exec(self.script_content)
                    else:
                        # 쉘 명령어 실행
                        subprocess.Popen(self.script_content, shell=True)
            except Exception as e:
                QMessageBox.warning(self, "오류", f"스크립트 실행 실패: {str(e)}")
        else:
            # 기존 button_clicked 로직
            if self.app_path:
                try:
                    if self.is_url:
                        subprocess.Popen(['open', self.app_path])
                    elif self.is_folder:
                        subprocess.Popen(['open', self.app_path])
                    else:
                        subprocess.Popen(['open', self.app_path])
                except Exception as e:
                    QMessageBox.warning(self, "오류", f"실행 실패: {str(e)}")
            else:
                QMessageBox.information(self, "알림", "먼저 앱, 폴더 또는 URL을 설정해주세요.")

    def show_context_menu(self, pos):
        context_menu = QMenu(self)


        # 기본 설정
        set_name_action = context_menu.addAction("이름 설정")
        set_shortcut_action = context_menu.addAction("단축키 설정")

        # 연결 설정 그룹
        connect_menu = context_menu.addMenu("연결 설정")
        set_app_action = connect_menu.addAction("앱 설정")
        set_folder_action = connect_menu.addAction("폴더 설정")
        set_url_action = connect_menu.addAction("URL 설정")
        connect_menu.addSeparator()
        set_smb_action = connect_menu.addAction("SMB 연결")
        set_afp_action = connect_menu.addAction("AFP 연결")

        # 스크립트 설정 그룹
        script_menu = context_menu.addMenu("스크립트 설정")
        set_python_script = script_menu.addAction("Python 스크립트")
        set_shell_command = script_menu.addAction("쉘 명령어")

        # 문서 프린트 설정
        if self.app_path and self.app_path.endswith(('.doc', '.docx', '.pdf', '.txt', '.rtf', '.pages', '.xls', '.xlsx', '.csv')):
            context_menu.addSeparator()
            print_action = context_menu.addAction("문서 프린트")

        # 스타일 설정 그룹
        style_menu = context_menu.addMenu("스타일 설정")

        # 아이콘 설정 서브메뉴
        icon_menu = style_menu.addMenu("아이콘 설정")
        set_icon_action = icon_menu.addAction("아이콘 추가")
        remove_icon_action = icon_menu.addAction("아이콘 제거")

        # 배경 설정 서브메뉴
        background_menu = style_menu.addMenu("배경 설정")
        set_color_action = background_menu.addAction("배경색 설정")
        set_background_image_action = background_menu.addAction("배경 이미지 설정")
        remove_background_image_action = background_menu.addAction("배경 이미지 제거")

        set_text_color_action = style_menu.addAction("텍스트 색상 설정")
        set_font_size_action = style_menu.addAction("글자 크기 설정")

        # 전송 설정 그룹
        transfer_menu = context_menu.addMenu("전송 설정")
        set_transfer_action = transfer_menu.addAction("전송 버튼 만들기")

        context_menu.addSeparator()
        reset_action = context_menu.addAction("초기화")

        action = context_menu.exec_(self.mapToGlobal(pos))

        if action == set_name_action:
            self.set_button_name()
        elif action == set_app_action:
            self.set_app_path()
        elif action == set_folder_action:
            self.set_folder_path()
        elif action == set_url_action:
            self.set_url_path()
        elif action == set_smb_action:
            self.set_smb_path()
        elif action == set_afp_action:
            self.set_afp_path()
        elif action == set_python_script:
            self.set_python_script()
        elif action == set_shell_command:
            self.set_shell_command()
        elif action == set_icon_action:
            self.set_icon()
        elif action == remove_icon_action:
            self.remove_icon()
        elif action == set_color_action:
            self.set_button_color()
        elif action == set_background_image_action:
            self.set_background_image()
        elif action == remove_background_image_action:
            self.remove_background_image()
        elif action == set_text_color_action:
            self.set_text_color()
        elif action == set_font_size_action:
            self.set_font_size()
        elif action == reset_action:
            self.reset_button()
        elif 'print_action' in locals() and action == print_action:
            try:
                subprocess.Popen(['lpr', self.app_path])
            except Exception as e:
                QMessageBox.warning(self, "오류", f"프린트 실패: {str(e)}")
        elif action == set_shortcut_action:
            self.set_shortcut()
        elif action == set_transfer_action:
            self.setText("전송 버튼")
            self.clicked.disconnect()
            self.clicked.connect(self.show_transfer_window)
            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/NetBootVolume.icns"
            self.update_style()
            self.app_path = ""
            self.save_settings()

    def show_transfer_window(self):
        transfer_window = QDialog(self)
        transfer_window.setWindowTitle("파일 전송")
        transfer_window.setFixedSize(400, 800)
        transfer_window.setWindowFlags(transfer_window.windowFlags() | Qt.WindowStaysOnTopHint)

        layout = QVBoxLayout()

        # 리스트박스 생성
        list_widget = QListWidget()
        list_widget.setAcceptDrops(True)
        list_widget.setDragDropMode(QListWidget.DragDrop)
        list_widget.setSelectionMode(QListWidget.ExtendedSelection)
        def keyPressEvent(event):
            if event.key() in (Qt.Key_Return, Qt.Key_Enter):
                return
            super(QListWidget, list_widget).keyPressEvent(event)


        list_widget.keyPressEvent = keyPressEvent
        layout.addWidget(list_widget)

        path_layout = QVBoxLayout()

        # 라디오 버튼 그룹 생성
        radio_group = QButtonGroup()

        # 기본 경로 라디오 버튼
        default_radio = QRadioButton("기본 경로 (/Users/usabatch/Desktop)")
        default_radio.setChecked(True)
        radio_group.addButton(default_radio)

        # 수동 입력 라디오 버튼
        custom_radio = QRadioButton("수동 입력")
        radio_group.addButton(custom_radio)

        # 수동 입력 텍스트 필드
        custom_path_input = QLineEdit()
        custom_path_input.setPlaceholderText("경로를 입력하세요")
        custom_path_input.setEnabled(False)

        # 라디오 버튼 상태에 따라 텍스트 필드 활성화/비활성화
        def toggle_custom_input():
            custom_path_input.setEnabled(custom_radio.isChecked())

        custom_radio.toggled.connect(toggle_custom_input)

        path_layout.addWidget(default_radio)
        path_layout.addWidget(custom_radio)
        path_layout.addWidget(custom_path_input)

        layout.addLayout(path_layout)

        # 버튼 레이아웃
        button_layout = QHBoxLayout()

        # 초기화 버튼
        clear_button = QPushButton("초기화")
        clear_button.setFocusPolicy(Qt.NoFocus)
        clear_button.clicked.connect(list_widget.clear)

        # 선택 삭제 버튼
        delete_button = QPushButton("선택 삭제")
        delete_button.setFocusPolicy(Qt.NoFocus)
        def delete_selected():
            for item in list_widget.selectedItems():
                list_widget.takeItem(list_widget.row(item))
        delete_button.clicked.connect(delete_selected)

        button_layout.addWidget(clear_button)
        button_layout.addWidget(delete_button)
        button_layout.addStretch()

        layout.addLayout(button_layout)

        ip_container = QVBoxLayout()

        # IP 입력 필드를 담을 리스트
        ip_layouts = []

        def create_ip_input():
            # 각 IP 입력을 위한 수평 레이아웃
            ip_layout = QHBoxLayout()

            ip_prefix = QLabel("192.168.")
            ip_input = QLineEdit()
            ip_input.setMaxLength(15)  # 범위 입력을 위해 최대 길이 증가
            ip_input.setFixedWidth(120)  # 범위 입력을 위해 너비 증가

            # + 버튼 생성
            add_button = QPushButton("+")
            add_button.setFocusPolicy(Qt.NoFocus)
            add_button.setFixedWidth(30)
            add_button.clicked.connect(create_ip_input)

            # - 버튼 생성
            remove_button = QPushButton("-")
            remove_button.setFocusPolicy(Qt.NoFocus)
            remove_button.setFixedWidth(30)
            remove_button.clicked.connect(lambda: remove_ip_input(ip_layout))

            ip_layout.addWidget(ip_prefix)
            ip_layout.addWidget(ip_input)
            ip_layout.addWidget(add_button)
            ip_layout.addWidget(remove_button)
            ip_layout.addStretch()

            ip_container.addLayout(ip_layout)
            ip_layouts.append(ip_layout)

            # 첫 번째 IP 입력 필드의 경우 - 버튼 비활성화
            if len(ip_layouts) == 1:
                remove_button.setEnabled(False)
            else:
                # 이전 IP 입력의 + 버튼 비활성화
                prev_layout = ip_layouts[-2]
                prev_layout.itemAt(2).widget().setEnabled(False)

        def remove_ip_input(layout):
            while layout.count():
                item = layout.takeAt(0)
                if item.widget():
                    item.widget().deleteLater()

            ip_layouts.remove(layout)
            ip_container.removeItem(layout)

            if ip_layouts:
                last_layout = ip_layouts[-1]
                last_layout.itemAt(2).widget().setEnabled(True)

        # 첫 번째 IP 입력 필드 생성
        create_ip_input()

        # 전송 버튼
        send_button = QPushButton("전송")
        send_button.setFocusPolicy(Qt.NoFocus)

        # 버튼 레이아웃
        button_layout = QHBoxLayout()
        button_layout.addStretch()
        button_layout.addWidget(send_button)

        layout.addLayout(ip_container)
        layout.addLayout(button_layout)
        transfer_window.setLayout(layout)

        def dragEnterEvent(event):
            if event.mimeData().hasUrls():
                event.accept()
            else:
                event.ignore()

        def dragMoveEvent(event):
            if event.mimeData().hasUrls():
                event.accept()
            else:
                event.ignore()

        def handle_drop(event):
            if event.mimeData().hasUrls():
                for url in event.mimeData().urls():
                    file_path = url.toLocalFile()
                    # 폴더/파일 구분하여 처리
                    if os.path.isdir(file_path):
                        # 폴더인 경우
                        folder_name = os.path.basename(os.path.normpath(file_path))
                        item = QListWidgetItem(folder_name)
                        item.setData(Qt.UserRole, file_path)
                        item.setIcon(QApplication.style().standardIcon(QStyle.SP_DirIcon))
                    else:
                        # 파일인 경우
                        item = QListWidgetItem(os.path.basename(file_path))
                        item.setData(Qt.UserRole, file_path)
                    list_widget.addItem(item)
                event.accept()
            else:
                event.ignore()

        def transfer_files():
            ip_addresses = []
            for ip_layout in ip_layouts:
                ip_input = ip_layout.itemAt(1).widget()
                ip_text = ip_input.text()

                if '~' in ip_text:
                    try:
                        start_ip, end_ip = ip_text.split('~')
                        # 시작 IP와 끝 IP에서 마지막 숫자만 추출
                        start_num = int(start_ip.strip().split('.')[-1])
                        end_num = int(end_ip.strip().split('.')[-1])

                        # IP 범위 생성
                        for i in range(start_num, end_num + 1):
                            ip_addresses.append(f"0.{i}")
                    except ValueError:
                        QMessageBox.warning(transfer_window, "오류", "올바른 IP 범위를 입력하세요")
                        return
                else:
                    if ip_text:
                        ip_addresses.append(ip_text)

            if not ip_addresses:
                QMessageBox.warning(transfer_window, "오류", "올바른 IP를 입력하세요")
                return

            if default_radio.isChecked():
                target_path = "/Users/usabatch/Desktop"
            else:
                target_path = custom_path_input.text()
                if not target_path:
                    QMessageBox.warning(transfer_window, "오류", "경로를 입력하세요")
                    return

            # 비밀번호 입력 다이얼로그 생성
            password_dialog = QDialog(transfer_window)
            password_dialog.setWindowTitle("비밀번호 입력")
            password_dialog.setFixedSize(300, 100)
            password_dialog.setWindowFlags(password_dialog.windowFlags() | Qt.WindowStaysOnTopHint)

            dialog_layout = QVBoxLayout()
            password_input = QLineEdit()
            password_input.setEchoMode(QLineEdit.Password)
            password_input.setPlaceholderText("비밀번호를 입력하세요 (영문인지 확인)")

            ok_button = QPushButton("확인")
            ok_button.clicked.connect(password_dialog.accept)

            dialog_layout.addWidget(password_input)
            dialog_layout.addWidget(ok_button)
            password_dialog.setLayout(dialog_layout)

            if password_dialog.exec_() == QDialog.Accepted:
                password = password_input.text()
                if not password:
                    QMessageBox.warning(transfer_window, "오류", "비밀번호를 입력하세요")
                    return
                ssh_command = f'sshpass -p {password} ssh -o StrictHostKeyChecking=no'

                total_tasks = len(ip_addresses) * list_widget.count()

                # 프로그레스 다이얼로그 생성
                progress_dialog = QProgressDialog("파일 전송 준비 중...", "취소", 0, total_tasks, transfer_window)
                progress_dialog.setWindowTitle("전송 진행률")
                progress_dialog.setWindowModality(Qt.WindowModal)
                progress_dialog.setAutoClose(True)
                progress_dialog.setMinimumDuration(0)  # 즉시 표시
                progress_dialog.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint)
                progress_dialog.show()  # 명시적으로 표시

                current_progress = 0
                transfer_success = True

                for ip in ip_addresses:
                    target_ip = f"192.168.{ip}"
                    for i in range(list_widget.count()):
                        if progress_dialog.wasCanceled():
                            return

                        file_path = list_widget.item(i).data(Qt.UserRole)
                        file_name = os.path.basename(file_path)
                        progress_dialog.setLabelText(f"전송 중: {file_name}\nIP: {target_ip}")
                        try:
                            SSHPASS_PATH = "/usr/local/bin/sshpass"

                            # rsync 명령어 수정
                            result = subprocess.run(
                                [SSHPASS_PATH, '-p', password, 'rsync', '-avzP',
                                '-e', 'ssh -o StrictHostKeyChecking=no',
                                file_path,
                                f'usabatch@{target_ip}:{target_path}'],
                                capture_output=True,
                                text=True
                            )
                        except subprocess.CalledProcessError as e:
                            QMessageBox.warning(transfer_window, "오류",
                                            f"전송 실패: {e.stderr}")
                            transfer_success = False
                            return

                        current_progress += 1
                        progress_dialog.setValue(current_progress)

                    if not transfer_success:
                        break
                progress_dialog.close()
                # 전송 성공 메시지 표시 후에도 리스트 유지
                msg_box = QMessageBox()
                msg_box.setIcon(QMessageBox.Information)
                msg_box.setWindowTitle("성공")
                msg_box.setText("파일 전송이 완료되었습니다")
                msg_box.setStandardButtons(QMessageBox.Ok)
                msg_box.setDefaultButton(QMessageBox.Ok)
                msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowStaysOnTopHint)
                msg_box.exec_()
        # 이벤트 핸들러 연결
        list_widget.dragEnterEvent = dragEnterEvent
        list_widget.dragMoveEvent = dragMoveEvent
        list_widget.dropEvent = handle_drop
        send_button.clicked.connect(transfer_files)

        # 설정 저장
        self.setText("전송 버튼")
        self.app_path = ""
        self.save_settings()

        transfer_window.exec_()

    def remove_icon(self):
        self.icon_path = ""
        self.setIcon(QIcon())
        self.update_style()
        self.save_settings()

    def set_background_image(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "배경 이미지 선택",
            "",
            "이미지 파일 (*.png *.jpg *.jpeg *.gif);;모든 파일 (*.*)"
        )
        if file_path:
            # 이미지 로드 및 크기 조정
            image = QImage(file_path)
            scaled_image = image.scaled(self.width(), self.height(),
                                    Qt.KeepAspectRatio,
                                    Qt.SmoothTransformation)

            # 임시 파일로 저장
            temp_path = f"/tmp/button_bg_{self.id}.png"
            scaled_image.save(temp_path)
            self.background_image = temp_path

            self.update_style()
            self.save_settings()


    def remove_background_image(self):
        self.background_image = ""
        self.update_style()
        self.save_settings()

    def update_style(self):
        style = f"""
            QToolButton {{
                background-color: {self.button_color};
                color: {self.text_color};
                border: 2px solid #8f8f91;
                border-radius: 6px;
                padding: 5px;
                font-size: {self.font_size}px;
                font-weight: bold;
        """

        if hasattr(self, 'background_image') and self.background_image:
            style += f"""
                background-image: url({self.background_image});
                background-position: center;
                background-repeat: no-repeat;
            """

        style += f"""
            }}
            QToolButton:hover {{
                background-color: {self.button_color};
                border: 2px solid #1c1c1c;
            }}
            QToolButton:pressed {{
                background-color: {self.darken_color(self.button_color)};
                border: 2px solid #1c1c1c;
                padding-left: 7px;
                padding-top: 7px;
            }}
        """

        self.setStyleSheet(style)

        if self.icon_path:
            icon = QIcon(self.icon_path)
            self.setIcon(icon)
            self.setIconSize(QSize(60, 60))

    def set_python_script(self):
        script, ok = QInputDialog.getMultiLineText(
            self, "Python 스크립트 설정",
            "실행할 Python 스크립트를 입력하세요:",
            self.script_content if self.is_script else ""
        )
        if ok:
            self.script_content = script
            self.is_script = True
            self.is_url = False
            self.is_folder = False
            self.save_settings()

    def set_shell_command(self):
        command, ok = QInputDialog.getText(
            self, "쉘 명령어 설정",
            "실행할 쉘 명령어를 입력하세요:",
            text=self.script_content if self.is_script else ""
        )
        if ok:
            self.script_content = command
            self.is_script = True
            self.is_url = False
            self.is_folder = False
            self.save_settings()

    def is_python_script(self):
        # Python 스크립트인지 판단
        return any(keyword in self.script_content for keyword in ['import ', 'def ', 'class ', 'print'])

    def set_smb_path(self):
        smb_path, ok = QInputDialog.getText(
            self,
            "SMB 연결",
            "SMB 경로를 입력하세요 (예: smb://서버주소/공유폴더):",
            text="smb://"
        )
        if ok and smb_path:
            if not smb_path.startswith('smb://'):
                smb_path = 'smb://' + smb_path
            self.app_path = smb_path
            self.is_url = False
            self.is_folder = True

            # 공유 폴더 이름을 버튼 텍스트로 설정
            folder_name = smb_path.rstrip('/').split('/')[-1]
            self.setText(folder_name)

            # SMB 아이콘 설정
            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericFileServerIcon.icns"
            self.update_style()
            self.save_settings()

    def set_afp_path(self):
        afp_path, ok = QInputDialog.getText(
            self,
            "AFP 연결",
            "AFP 경로를 입력하세요 (예: afp://서버주소/공유폴더):",
            text="afp://"
        )
        if ok and afp_path:
            if not afp_path.startswith('afp://'):
                afp_path = 'afp://' + afp_path
            self.app_path = afp_path
            self.is_url = False
            self.is_folder = True

            # 공유 폴더 이름을 버튼 텍스트로 설정
            folder_name = afp_path.rstrip('/').split('/')[-1]
            self.setText(folder_name)

            # AFP 아이콘 설정
            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Accounts.icns"
            self.update_style()
            self.save_settings()

    def button_clicked(self):
        if self.app_path:
            try:
                if self.is_url:
                    subprocess.Popen(['open', self.app_path])
                elif self.is_folder:
                    # SMB나 AFP URL인 경우에도 'open' 명령 사용
                    if self.app_path.startswith(('smb://', 'afp://')):
                        subprocess.Popen(['open', self.app_path])
                    else:
                        subprocess.Popen(['open', self.app_path, '--args', 'specific_parameter'])
                else:
                    if self.app_path.endswith('.py'):
                        subprocess.Popen(['open', '-a', 'Visual Studio Code', self.app_path])
                    elif self.app_path.endswith('.sh'):
                        subprocess.Popen(['open', '-a', 'Terminal', self.app_path])
                    elif self.app_path.endswith('.txt'):
                        subprocess.Popen(['open', '-a', 'TextEdit', self.app_path])
                    elif self.app_path.endswith(('.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.odt', '.ods', '.odp')):
                        subprocess.Popen(['open', '-a', '/Applications/LibreOffice.app', self.app_path])
                    elif self.app_path.endswith(('.mp4', '.mov', '.avi', '.mkv', '.m4v')):
                        subprocess.Popen(['open', '-a', '/System/Applications/QuickTime Player.app', self.app_path])
                    elif self.app_path.endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.pdf')):
                        subprocess.Popen(['open', '-a', 'Preview', self.app_path])
                    else:
                        subprocess.Popen(['open', self.app_path])
            except Exception as e:
                print(f"실행 오류: {str(e)}")
                QMessageBox.warning(self, "오류", f"실행 실패: {str(e)}")
        else:
            QMessageBox.information(self, "알림", "먼저 앱, 폴더 또는 URL을 설정해주세요.")

    def set_button_name(self):
        current_name = self.text() if self.text() != "설정하기" else ""
        name, ok = QInputDialog.getText(
            self,
            "버튼 이름 설정",
            "버튼 이름을 입력하세요:",
            text=current_name
        )
        if ok and name:
            self.setText(name)
            self.save_settings()

    def set_button_color(self):
        color = QColorDialog.getColor(QColor(self.button_color), self, "배경색 선택")
        if color.isValid():
            self.button_color = color.name()
            self.update_style()
            self.save_settings()

    def set_text_color(self):
        color = QColorDialog.getColor(QColor(self.text_color), self, "텍스트 색상 선택")
        if color.isValid():
            self.text_color = color.name()
            self.update_style()
            self.save_settings()

    def set_font_size(self):
        size, ok = QInputDialog.getInt(
            self,
            "글자 크기 설정",
            "글자 크기를 입력하세요 (8-30):",
            value=self.font_size,
            min=8,
            max=30
        )
        if ok:
            self.font_size = size
            self.update_style()
            self.save_settings()

    def set_url_path(self):
        current_url = self.app_path if self.is_url else "https://"
        url, ok = QInputDialog.getText(
            self,
            "URL 설정",
            "URL을 입력하세요 (예: https://www.google.com):",
            text=current_url
        )
        if ok and url:
            if not url.startswith(('http://', 'https://')):
                url = 'https://' + url
            self.app_path = url
            self.is_url = True
            self.is_folder = False

            # URL 도메인을 버튼 텍스트로 설정
            domain = url.split('//')[1].split('/')[0]
            self.setText(domain)

            # URL 기본 아이콘 설정
            self.icon_path = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericURLIcon.icns"
            self.update_style()
            self.save_settings()

    def set_icon(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "아이콘 이미지 선택",
            "/Applications",
            "모든 파일 (*.*);;이미지 파일 (*.png *.jpg *.jpeg *.gif *.ico *.icns);;앱 파일 (*.app)"
        )
        if file_path:
            if file_path.endswith('.app'):
                # .app 파일이 선택된 경우 Contents/Resources 폴더 내 아이콘 검색
                resources_path = os.path.join(file_path, 'Contents', 'Resources')
                app_name = os.path.basename(file_path).replace('.app', '')

                # 아이콘 후보 목록에 앱 이름으로 된 .icns 파일 추가
                icon_candidates = [
                    'AppIcon.icns',
                    'Icon.icns',
                    'icon.icns',
                    f'{app_name}.icns',  # 앱 이름으로 된 .icns 파일
                    f'{app_name.lower()}.icns'  # 소문자로 된 앱 이름 .icns 파일
                ]

                for icon_name in icon_candidates:
                    icon_path = os.path.join(resources_path, icon_name)
                    if os.path.exists(icon_path):
                        self.icon_path = icon_path
                        break
            else:
                # 일반 이미지 파일이 선택된 경우
                self.icon_path = file_path

            self.update_style()
            self.save_settings()

    def set_folder_path(self):
        folder_path = QFileDialog.getExistingDirectory(
            self,
            "폴더 선택",
            "/",
            QFileDialog.ShowDirsOnly
        )
        if folder_path:
            self.app_path = folder_path
            self.is_folder = True
            self.is_url = False
            self.save_settings()

    def set_app_path(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "실행할 앱 선택",
            "/Applications",
            "애플리케이션 (*.app);;모든 파일 (*.*)"
        )
        if file_path:
            self.app_path = file_path
            self.is_folder = False
            self.is_url = False

            # 앱 이름을 버튼 텍스트로 설정
            if file_path.endswith('.app'):
                app_name = os.path.basename(file_path).replace('.app', '')
                self.setText(app_name)

                try:
                    resources_path = os.path.join(file_path, 'Contents', 'Resources')
                    # 기본 아이콘 후보
                    icon_candidates = [
                        'AppIcon.icns',
                        'Icon.icns',
                        'icon.icns',
                        f'{app_name}.icns',
                        'Harmony.icns',  # Harmony 전용 아이콘
                        'HarmonyPremium.icns'  # Harmony Premium 전용 아이콘
                    ]

                    # 아이콘 파일 찾기
                    for icon_name in icon_candidates:
                        icon_path = os.path.join(resources_path, icon_name)
                        if os.path.exists(icon_path):
                            self.icon_path = icon_path
                            break

                except Exception as e:
                    print(f"아이콘 설정 중 오류 발생: {str(e)}")

            self.update_style()
            self.save_settings()

    def reset_button(self):
        self.setText("설정하기")
        self.app_path = ""
        self.icon_path = ""
        self.is_folder = False
        self.is_url = False
        self.button_color = "#FFFFFF"
        self.text_color = "#000000"
        self.font_size = 12
        if hasattr(self, 'background_image'):
            self.background_image = ""  # 배경 이미지 초기화
        if self.shortcut is not None:
            self.shortcut.setEnabled(False)
            self.shortcut.deleteLater()
        self.shortcut = None
        self.shortcut_text = ""
        self.shortcut_label.hide()
        self.shortcut_label.update()  # 라벨 강제 업데이트
        if hasattr(self, 'show_transfer_window'):
            self.clicked.disconnect()
            self.clicked.connect(lambda: QMessageBox.information(self, "알림", "먼저 앱, 폴더 또는 URL을 설정해주세요."))
        self.setIcon(QIcon())
        self.update_style()
        self.save_settings()

    def save_settings(self):
        settings = StreamDeck.load_all_settings()
        settings[str(self.id)] = {
            "name": self.text(),
            "app_path": self.app_path,
            "icon_path": self.icon_path,
            "is_folder": self.is_folder,
            "is_url": self.is_url,
            "is_transfer": self.text() == "전송 버튼",  # 전송 버튼 여부 저장
            "color": self.button_color,
            "text_color": self.text_color,
            "font_size": self.font_size,
            "background_image": self.background_image if hasattr(self, 'background_image') else "",
            "shortcut": self.shortcut_text # 단축키 텍스트 저장
        }
        StreamDeck.save_all_settings(settings)

    def load_settings(self):
        settings = StreamDeck.load_all_settings()
        if str(self.id) in settings:
            button_settings = settings[str(self.id)]
            self.setText(button_settings.get("name", "설정하기"))
            self.app_path = button_settings.get("app_path", "")
            self.icon_path = button_settings.get("icon_path", "")
            self.is_folder = button_settings.get("is_folder", False)
            self.is_url = button_settings.get("is_url", False)
            if button_settings.get("is_transfer", False):
                self.setText("전송 버튼")
                self.clicked.disconnect()
                self.clicked.connect(self.show_transfer_window)
            self.button_color = button_settings.get("color", "#FFFFFF")
            self.text_color = button_settings.get("text_color", "#000000")
            self.font_size = button_settings.get("font_size", 12)
            self.background_image = button_settings.get("background_image", "")
            
            # 단축키 설정 불러오기
            shortcut_key = button_settings.get("shortcut", "")
            if shortcut_key:
                self.shortcut_text = shortcut_key

                # 기존 단축키 제거
                if hasattr(self, 'shortcut') and self.shortcut:
                    self.shortcut.setEnabled(False)
                    self.shortcut.deleteLater()

                # 새 단축키 설정
                self.shortcut = QShortcut(QKeySequence(shortcut_key), self)
                if self.text() == "전송 버튼":
                    self.shortcut.activated.connect(self.show_transfer_window)
                else:
                    self.shortcut.activated.connect(self.button_clicked)

                # 단축키 라벨 설정
                self.shortcut_label.setText(shortcut_key)
                self.shortcut_label.adjustSize()
                self.shortcut_label.move(self.width() - self.shortcut_label.width() - 5, 5)
                self.shortcut_label.show()
                self.shortcut_label.raise_()
            else:
                self.shortcut_text = ""
                if hasattr(self, 'shortcut') and self.shortcut:
                    self.shortcut.setEnabled(False)
                    self.shortcut.deleteLater()
                self.shortcut = None
                self.shortcut_label.hide()

            self.update_style()


class CustomListWidget(QListWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self.setDragDropMode(QListWidget.DragDrop)
        self.setSelectionMode(QListWidget.ExtendedSelection)

    def dragMoveEvent(self, e):
        if ((self.row(self.itemAt(e.pos())) == self.currentRow() + 1) or
            (self.currentRow() == self.count() - 1 and self.row(self.itemAt(e.pos())) == -1)):
            e.ignore()
        else:
            super().dragMoveEvent(e)


class StreamDeck(QWidget):
    SETTINGS_FILE = "/Users/usabatch/streamdeck_settings.json"

    def __init__(self):
        super().__init__()
        self.buttons = []
        self.is_pinned = False
        self.shortcut = None
        self.pin_shortcut = None
        self.auto_hide = False
        self.hide_timer = None
        self.screen = QApplication.primaryScreen().geometry()

        self.initUI()  # UI 먼저 초기화
        self.setup_pin_shortcut()  # 창 고정 단축키 설정
        self.setup_shortcuts()  # 자동 숨김 단축키 설정
        self.setup_auto_hide()  # 초기 위치 설정
        self.setup_size_shortcuts()  # 확대/축소 단축키 설정 추가

        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon("/Users/usabatch/coding/YesonButton_buildapp/button.icns"))  # 아이콘 설정

        # 트레이 메뉴 생성
        self.tray_menu = QMenu()
        self.show_action = self.tray_menu.addAction("보이기")
        self.hide_action = self.tray_menu.addAction("숨기기")
        self.quit_action = self.tray_menu.addAction("종료")

        # 메뉴 동작 연결
        self.show_action.triggered.connect(self.show)
        self.hide_action.triggered.connect(self.hide)
        self.quit_action.triggered.connect(QApplication.instance().quit)

        # 트레이 아이콘에 메뉴 설정
        self.tray_icon.setContextMenu(self.tray_menu)
        self.tray_icon.show()

        # 트레이 아이콘 클릭 시 UI 표시/숨기기
        self.tray_icon.activated.connect(self.tray_icon_activated)

    def setup_size_shortcuts(self):
        """창 크기 확대/축소 단축키 설정"""
        # 1번 키: 축소
        self.decrease_shortcut = QShortcut(QKeySequence("1"), self)
        self.decrease_shortcut.activated.connect(self.decrease_size)
        self.decrease_shortcut.setContext(Qt.ApplicationShortcut)  # 애플리케이션 전체에서 작동

        # 2번 키: 확대
        self.increase_shortcut = QShortcut(QKeySequence("2"), self)
        self.increase_shortcut.activated.connect(self.increase_size)
        self.increase_shortcut.setContext(Qt.ApplicationShortcut) # 애플리케이션 전체에서 작동
    def increase_size(self):
        """창 크기를 확대"""
        current_size = self.size()
        new_width = min(self.screen.width(), current_size.width() + 50)  # 최대 화면 너비 제한
        new_height = min(self.screen.height(), current_size.height() + 30) #최대 화면 높이 제한
        self.resize(new_width, new_height)


    def decrease_size(self):
        """창 크기를 축소"""
        current_size = self.size()
        new_width = max(self.minimumWidth(), current_size.width() - 50)   # 최소 너비 제한
        new_height = max(self.minimumHeight(), current_size.height() - 30)  # 최소 높이 제한
        self.resize(new_width, new_height)

    def tray_icon_activated(self, reason):
        if reason == QSystemTrayIcon.Trigger:  # 클릭 시
            if self.isVisible():
                self.hide()
            else:
                self.show()

    def setup_shortcuts(self):
        # Alt+Space 단축키 설정
        self.toggle_shortcut = QShortcut(QKeySequence("Alt+Space"), self)
        self.toggle_shortcut.activated.connect(self.toggle_auto_hide)
        self.toggle_shortcut.setContext(Qt.ApplicationShortcut)

    def setup_auto_hide(self):
        # 모든 스크린 정보 가져오기
        screens = QApplication.screens()
        if len(screens) > 1:  # 듀얼 모니터인 경우
            self.screen = screens[1].geometry()  # 두 번째 모니터 선택
        else:
            self.screen = QApplication.primaryScreen().geometry()

        self.auto_hide = True
        self.hide_timer = None
        self.hide_direction = 'right' if self.x() > self.screen.width() // 2 else 'left'

        # 탭 버튼 생성 (부모를 None으로 설정하여 독립적인 창으로 만듦)
        self.tab_button = QPushButton("≡")
        self.tab_button.setFixedSize(20, 60)
        self.tab_button.setStyleSheet("""
            QPushButton {
                background-color: #4a9eff;
                color: white;
                border: none;
                border-radius: 3px;
                font-size: 16px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #3989e3;
            }
        """)
        self.tab_button.clicked.connect(self.show_window)
        self.tab_button.hide()
        self.tab_button.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool)

    def show_tab(self, x_pos):
        # UI 창의 현재 위치를 기준으로 탭 버튼 배치
        if self.hide_direction == 'left':
            x_pos = max(0, self.x() + 5)  # 화면 왼쪽 경계 확인
        else:
            # 화면 오른쪽 경계 확인
            screens = QApplication.screens()
            if len(screens) > 1:
                screen_width = self.screen.x() + self.screen.width()
            else:
                screen_width = self.screen.width()
            x_pos = min(screen_width - self.tab_button.width(), self.x() + self.width() - 5)

        # 탭 버튼을 창의 중앙 높이에 배치
        y_pos = max(0, min(self.y() + (self.height() - self.tab_button.height()) // 2,
                        self.screen.height() - self.tab_button.height()))

        self.tab_button.move(x_pos, y_pos)
        self.tab_button.show()
        self.tab_button.raise_()

    def enterEvent(self, event):
        if self.auto_hide and not self.is_pinned:
            if self.hide_timer:
                self.hide_timer.stop()
            self.show_window()
        super().enterEvent(event)

    def leaveEvent(self, event):
        if self.auto_hide and not self.is_pinned:
            # 현재 창의 위치에 따라 숨김 방향 설정
            screen_center = self.screen.x() + (self.screen.width() // 2)
            self.hide_direction = 'right' if self.x() > screen_center else 'left'

            # 마우스가 창을 벗어날 때 타이머 설정
            if self.hide_timer:
                self.hide_timer.stop()
            self.hide_timer = QTimer(self)
            self.hide_timer.timeout.connect(self.check_hide)
            self.hide_timer.setSingleShot(True)
            self.hide_timer.start(1000)
        super().leaveEvent(event)

    def check_hide(self):
        if not self.isVisible():
            return

        screen_center = self.screen.x() + (self.screen.width() // 2)
        window_right_edge = self.x() + self.width()
        screen_right_edge = self.screen.x() + self.screen.width()

        # 창이 왼쪽에 있는 경우
        if self.x() < screen_center:
            if self.x() <= self.screen.x() + 20:  # 왼쪽 경계 근처
                self.hide_direction = 'left'
                self.hide_window()
        # 창이 오른쪽에 있는 경우
        else:
            if window_right_edge >= screen_right_edge - 20:  # 오른쪽 경계 근처
                self.hide_direction = 'right'
                self.hide_window()

    def show_window(self):
        self.tab_button.hide()
        animation = QPropertyAnimation(self, b"geometry", self)
        animation.setDuration(200)
        animation.setEasingCurve(QEasingCurve.OutCubic)

        if self.hide_direction == 'left':
            new_x = 0
        else:
            new_x = self.screen.x() + self.screen.width() - self.width()

        animation.setEndValue(QRect(
            new_x,
            self.y(),
            self.width(),
            self.height()
        ))
        animation.start()

    def hide_window(self):
        animation = QPropertyAnimation(self, b"geometry", self)
        animation.setDuration(200)
        animation.setEasingCurve(QEasingCurve.InCubic)

        # UI 창의 현재 위치를 기준으로 숨김 위치와 탭 버튼 위치 계산
        if self.hide_direction == 'left':
            new_x = self.x() - self.width() + 5
            tab_x = self.x() + 5
        else:
            new_x = self.x() + self.width() - 5
            tab_x = self.x() + self.width() - self.tab_button.width() - 5

        animation.setEndValue(QRect(
            new_x,
            self.y(),
            self.width(),
            self.height()
        ))

        current_tab_x = tab_x
        animation.finished.connect(lambda: self.show_tab(current_tab_x))
        animation.start()

    def toggle_pin(self):
        self.is_pinned = self.pin_button.isChecked()
        if self.is_pinned:
            # 고정 시 숨김 해제
            self.show_window()
        self.setWindowFlag(Qt.WindowStaysOnTopHint, self.is_pinned)
        self.show()
        self.save_window_settings()

    def toggle_auto_hide(self):
        self.auto_hide = not self.auto_hide
        if self.auto_hide:
            # 타이머가 실행 중이면 중지
            if self.hide_timer and self.hide_timer.isActive():
                self.hide_timer.stop()
            self.hide_direction = 'right' if self.x() > self.screen.width() // 2 else 'left'
            self.hide_window()
        else:
            self.show_window()

    def setup_pin_shortcut(self):
        # F3 키로 창 고정 단축키 설정
        self.pin_shortcut = QShortcut(QKeySequence("F3"), self)
        self.pin_shortcut.activated.connect(self.toggle_pin_shortcut)
        self.pin_shortcut.setContext(Qt.ApplicationShortcut)

    def toggle_pin_shortcut(self):
        # 창 고정 상태 토글 (단축키용)
        self.is_pinned = not self.is_pinned
        self.pin_button.setChecked(self.is_pinned)  # 버튼 상태 업데이트
        self.setWindowFlag(Qt.WindowStaysOnTopHint, self.is_pinned)
        self.show()
        self.save_window_settings()

    def toggle_pin(self):
        # 버튼 클릭용 토글
        self.is_pinned = self.pin_button.isChecked()
        self.setWindowFlag(Qt.WindowStaysOnTopHint, self.is_pinned)
        self.show()
        self.save_window_settings()

    def initUI(self):
        main_layout = QVBoxLayout()
        main_layout.setSpacing(0)
        main_layout.setContentsMargins(0, 0, 0, 0)

        # 상단 바 프레임
        top_frame = QFrame()
        top_frame.setFixedHeight(30)
        top_frame.setStyleSheet("""
            QFrame {
                background-color: #f0f0f0;
                border-bottom: 1px solid #cccccc;
            }
        """)
        top_layout = QHBoxLayout(top_frame)
        top_layout.setContentsMargins(5, 2, 2, 2)

        # 제목 라벨
        title_label = QLabel("커스텀 버튼")
        title_label.setStyleSheet("""
            QLabel {
                font-size: 11px;
                font-weight: bold;
                color: #333333;
            }
        """)

        button_control_frame = QFrame()
        button_control_layout = QHBoxLayout(button_control_frame)
        button_control_layout.setContentsMargins(0, 0, 0, 0)
        button_control_layout.setSpacing(2)

        # 레이블 추가
        button_label = QLabel("버튼 추가")
        button_label.setStyleSheet("""
            QLabel {
                font-size: 11px;
                color: #333333;
            }
        """)

        # 버튼 추가/제거 버튼
        add_button = QPushButton("+")
        add_button.setFixedSize(25, 25)
        add_button.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                border-radius: 3px;
                font-size: 16px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
        """)
        add_button.clicked.connect(self.add_button)

        remove_button = QPushButton("-")
        remove_button.setFixedSize(25, 25)
        remove_button.setStyleSheet("""
            QPushButton {
                background-color: #f44336;
                color: white;
                border: none;
                border-radius: 3px;
                font-size: 16px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #da190b;
            }
        """)
        remove_button.clicked.connect(self.remove_button)

        # 버튼 컨트롤 프레임에 위젯 추가
        button_control_layout.addWidget(button_label)
        button_control_layout.addWidget(add_button)
        button_control_layout.addWidget(remove_button)

        # 창 고정 버튼
        self.pin_button = QPushButton("창 고정 (F3)")  # 버튼 텍스트에 단축키 표시
        self.pin_button.setCheckable(True)  # False에서 True로 변경
        self.pin_button.setFixedSize(80, 25)
        self.pin_button.setStyleSheet("""
            QPushButton {
                background-color: #ffffff;
                color: #000000;
                border: 1px solid #cccccc;
                border-radius: 3px;
                font-size: 11px;
                padding: 3px;
            }
            QPushButton:checked {
                background-color: #4a9eff;
                color: white;
                border: 1px solid #2980b9;
            }
            QPushButton:hover {
                background-color: #f0f0f0;
            }
            QPushButton:checked:hover {
                background-color: #3989e3;
            }
        """)
        self.pin_button.clicked.connect(self.toggle_pin)

        # 닫기 버튼
        self.close_button = QPushButton("닫기")
        self.close_button.setFixedSize(50, 25)
        self.close_button.setStyleSheet("""
            QPushButton {
                background-color: #ff4d4d;
                color: white;
                border: none;
                border-radius: 3px;
                font-size: 11px;
                                padding: 3px;
            }
            QPushButton:hover {
                background-color: #ff0000;
            }
        """)
        self.close_button.clicked.connect(self.close)

        # 상단 바 레이아웃에 위젯 추가
        top_layout.addWidget(title_label)
        top_layout.addStretch()
        top_layout.addWidget(button_control_frame)
        top_layout.addSpacing(10)
        top_layout.addWidget(self.pin_button)
        top_layout.addSpacing(5)
        top_layout.addWidget(self.close_button)

        # 그리드 레이아웃
        self.grid_layout = QGridLayout()
        self.grid_layout.setSpacing(5)
        self.grid_layout.setContentsMargins(5, 5, 5, 5)

        self.load_saved_buttons()

        main_layout.addWidget(top_frame)
        main_layout.addLayout(self.grid_layout)

        self.setLayout(main_layout)
        self.setWindowTitle('커스텀 버튼 - ver6.0')
        # 창을 resizable하도록 플래그 설정
        self.setWindowFlags(Qt.Window | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint)
        self.resize(600, 400)  # 초기 창 크기 설정
        self.load_window_settings()

        # 최소 크기 설정
        self.setMinimumSize(300, 230)  # 적절한 최소 크기로 조절

    def minimumSizeHint(self):
        """레이아웃에 필요한 최소 크기를 반환"""
        return QSize(300, 230)  # 상단바(30) + 버튼 최소 높이(100) * 2줄 + 여백

    def sizeHint(self):
        """레이아웃에 적절한 크기를 반환"""
        return QSize(600, 400)  # 초기 크기와 동일하게 하거나, 더 크게 설정


    def resizeEvent(self, event):
        """창 크기가 변경될 때 버튼 크기를 동적으로 조절"""
        super().resizeEvent(event)
        self.update_button_sizes()

    def update_button_sizes(self):
        """버튼 크기를 창 크기에 맞춰 업데이트"""
        num_cols = 5  # 한 행당 버튼 수
        if self.grid_layout.count() > 0:
            spacing = self.grid_layout.spacing()

            # 사용 가능한 너비 계산 (여백과 간격 제외)
            available_width = self.width() - self.grid_layout.contentsMargins().left() - self.grid_layout.contentsMargins().right() - (spacing * (num_cols - 1))
            button_width = max(100, available_width // num_cols)  # 최소 100

            num_rows = (self.grid_layout.count() + num_cols - 1) // num_cols
            available_height = self.height() - self.grid_layout.contentsMargins().top() - self.grid_layout.contentsMargins().bottom() - (spacing * (num_rows - 1)) - 30  # 상단바
            button_height = max(100, available_height // num_rows)

            for button in self.buttons:
                # 최대 크기와 고정 크기를 함께 설정하여 축소 가능하게 함
                button.setMaximumSize(button_width, button_height)  # 최대 크기 제한
                button.setFixedSize(button_width, button_height)

    def add_button(self):
        # 현재 버튼 수 확인
        current_buttons = len(self.buttons)

        # 새 버튼 생성
        new_button = CustomButton(current_buttons)
        self.buttons.append(new_button)

        # 그리드에 버튼 추가
        row = current_buttons // 5
        col = current_buttons % 5
        self.grid_layout.addWidget(new_button, row, col)

        # 버튼 설정 초기화 및 저장
        new_button.setText("설정하기")
        new_button.save_settings()

        # 전체 버튼 개수 저장
        self.save_buttons_count()

        # 버튼 크기 업데이트
        self.update_button_sizes()


    def remove_button(self):
        if self.buttons:
            # 마지막 버튼 제거
            button = self.buttons.pop()
            self.grid_layout.removeWidget(button)
            button.deleteLater()

            # 설정에서도 제거
            settings = self.load_all_settings()
            if str(button.id) in settings:
                del settings[str(button.id)]
            self.save_all_settings(settings)

            # 전체 버튼 개수 저장
            self.save_buttons_count()

            # 버튼 재배치
            self.rearrange_buttons()

            # 버튼 크기 업데이트
            self.update_button_sizes()

    def rearrange_buttons(self):
        # 모든 버튼을 일단 레이아웃에서 제거
        for button in self.buttons:
            self.grid_layout.removeWidget(button)

        # 버튼 재배치
        for i, button in enumerate(self.buttons):
            row = i // 5
            col = i % 5
            self.grid_layout.addWidget(button, row, col)

        # 레이아웃 업데이트
        self.grid_layout.update()

        # 창 새로고침
        self.repaint()



    def save_buttons_count(self):
        settings = self.load_all_settings()
        settings['buttons_count'] = len(self.buttons)
        self.save_all_settings(settings)

    def load_saved_buttons(self):
        settings = self.load_all_settings()
        buttons_count = settings.get('buttons_count', 15)  # 기본값 15개

        # 기존 버튼 모두 제거
        for button in self.buttons:
            self.grid_layout.removeWidget(button)
            button.deleteLater()
        self.buttons.clear()

        # 저장된 개수만큼 버튼 생성
        for i in range(buttons_count):
            button = CustomButton(i)
            self.buttons.append(button)
            row = i // 5
            col = i % 5
            self.grid_layout.addWidget(button, row, col)
            button.load_settings()

        # 버튼 크기 업데이트 (새로 추가된 버튼에 적용)
        self.update_button_sizes()

    def toggle_pin(self):
        self.is_pinned = self.pin_button.isChecked()
        self.setWindowFlag(Qt.WindowStaysOnTopHint, self.is_pinned)
        self.show()
        self.save_window_settings()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_position = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            new_pos = event.globalPos() - self.drag_position
            # 부드러운 이동을 위한 애니메이션
            animation = QPropertyAnimation(self, b"geometry", self)
            animation.setDuration(50)  # 짧은 지속 시간으로 부드러운 이동
            animation.setEndValue(QRect(new_pos.x(), new_pos.y(), self.width(), self.height()))
            animation.start(QPropertyAnimation.DeleteWhenStopped)

            # 현재 위치에 따라 숨김 방향 업데이트
            self.hide_direction = 'right' if self.x() > self.screen.width() // 2 else 'left'
        event.accept()

    def save_window_settings(self):
        settings = self.load_all_settings()
        settings['window'] = {
            'is_pinned': self.is_pinned,
            'position': {
                'x': self.x(),
                'y': self.y()
            },
            'auto_hide': self.auto_hide,
            'hide_direction': self.hide_direction
        }
        self.save_all_settings(settings)

    def load_window_settings(self):
        settings = self.load_all_settings()
        if 'window' in settings:
            window_settings = settings['window']
            self.is_pinned = window_settings.get('is_pinned', False)
            self.auto_hide = window_settings.get('auto_hide', True)
            self.hide_direction = window_settings.get('hide_direction', 'left')

            position = window_settings.get('position', {})
            if position:
                self.move(position.get('x', 300), position.get('y', 300))

            self.setWindowFlag(Qt.WindowStaysOnTopHint, self.is_pinned)
            self.pin_button.setChecked(self.is_pinned)

    def closeEvent(self, event):
        # 창이 닫힐 때 설정 저장
        self.save_window_settings()
        event.accept()

    @classmethod
    def load_all_settings(cls):
        if os.path.exists(cls.SETTINGS_FILE):
            try:
                with open(cls.SETTINGS_FILE, 'r') as f:
                    return json.load(f)
            except:
                return {}
        return {}

    @classmethod
    def save_all_settings(cls, settings):
        with open(cls.SETTINGS_FILE, 'w') as f:
            json.dump(settings, f)

    def swap_buttons(self, source_id, target_id):
        # 버튼 ID 찾기
        source_button = None
        target_button = None
        for button in self.buttons:
            if button.id == source_id:
                source_button = button
            elif button.id == target_id:
                target_button = button

        if source_button and target_button:
            # 그리드에서 현재 위치 가져오기
            source_index = self.buttons.index(source_button)
            target_index = self.buttons.index(target_button)

            # 버튼 위치 교환
            self.buttons[source_index], self.buttons[target_index] = self.buttons[target_index], self.buttons[source_index]

            # 그리드 레이아웃에서 버튼 재배치
            for i, button in enumerate(self.buttons):
                self.grid_layout.removeWidget(button)
                row = i // 5
                col = i % 5
                self.grid_layout.addWidget(button, row, col)
                button.id = i  # ID 업데이트

            # 설정 저장
            self.save_buttons_settings()

    def save_buttons_settings(self):
        # 모든 버튼의 설정 저장
        for button in self.buttons:
            button.save_settings()
        self.save_buttons_count()

def main():
    app = QApplication(sys.argv)
    deck = StreamDeck()
    deck.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()