import sys
import configparser
import os
import pandas as pd
import logging
from PyQt5.QtCore import Qt
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QFont
import re, json
from src.toggleSwitch import ToggleSwitch  # toggleSwitch.py 파일에서 ToggleSwitch 클래스를 임포트
from src.logger_module import setup_logger
import ctypes
from src.kipris_settingUI import SettingsDialog
from src.kipris_api_from_publicdata import Kipris_API
# from src.kipris_web_from_playwright import Kipris_WEB
from src.kiprisThread import *

def minimize_console():
    """ 콘솔 창을 최소화하는 함수 """
    hwnd = ctypes.windll.kernel32.GetConsoleWindow()
    if hwnd != 0:
        ctypes.windll.user32.ShowWindow(hwnd, 6)  # SW_MINIMIZE


class DeliveryFeeCalculator(QtWidgets.QWidget):
    def __init__(self, logger):
        super().__init__()
        self.logger = logger
        self.config = configparser.ConfigParser()
        self.config_path = 'config.ini'

        self.use_kipris = False
        self.usage_mode = "web"
        self.api_key = ""
        self.kiprisAPI = None
        self.searchThread = None  # 스레드 객체를 저장할 멤버 변수 추가
        self.asyncWorker = None
        self.search_keyword = None
        self.set_status =[]

        self.maxWeightSet = 25
        self.maxLengthSet = 100
        self.maxVolumeSet = 160
        self.currentMaxLength = 1
        self.roundVolume = 1
        self.currentWeight = 1
        self.currentVolume = 1
        self.fontSize = 14
        self.weightInterval = 0.5
        self.setSaveSetting = True

        self.addFee = 1000
        self.addFeeSetting = 20
        self.addFeeInterval = 5

        self.favoriteDelv = ""

        self.cargo_font = QFont()
        self.cargo_font_size = self.fontSize + 2

        self.deliveryFees = {}

        self.initSettings()

        self.initUI()
        self.loadDeliveryFees()
        self.setDefaultValues()
        self.kipris_Visible()

        self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)

        # self.setAddInterval(self.addFeeInterval)
        # self.setAddMoneySetting(self.addFee)
        self.setFontSize(self.fontSize)
        self.font_size_spinbox.setValue(self.fontSize)
        self.addMoney1_spinbox.setValue(self.addFeeSetting)
        self.addMoney2_spinbox.setValue(self.addFeeInterval)
        self.addMoney3_spinbox.setValue(self.addFee)
        self.saveSettingSwitch.setChecked(self.setSaveSetting)
        self.step_interval_spinbox.setValue(self.weightInterval)
        self.maxVolume_spinbox.setValue(self.maxVolumeSet)
        self.maxWeight_spinbox.setValue(self.maxWeightSet)
        self.maxLength_spinbox.setValue(self.maxLengthSet)
        self.setComboBox()

    def initSettings(self):
        # self.settings = QtCore.QSettings('When_Ride_Mycar_Tanya', 'DeliveryFeeCalculator')
        self.loadSettings()
        self.load_history()

        self.user_settings = {
            'use_kipris': self.use_kipris,
            'usage_mode': self.usage_mode,
            'api_key': self.api_key,
        }
        self.settingDialog = SettingsDialog(parent=self, initial_settings=self.user_settings)

    def loadSettings(self):
        """ 설정 파일을 불러옵니다. """
        try:
            if not os.path.exists(self.config_path):
                self.create_default_settings()
            self.config.read(self.config_path)
            
            self.maxWeightSet = self.config.getint('Settings', 'maxWeightSet', fallback=25)
            self.maxLengthSet = self.config.getint('Settings', 'maxLengthSet', fallback=100)
            self.maxVolumeSet = self.config.getint('Settings', 'maxVolumeSet', fallback=160)
            self.addFeeInterval = self.config.getint('Settings', 'addFeeInterval', fallback=5)
            self.addFeeSetting = self.config.getint('Settings', 'addFeeSetting', fallback=20)
            self.addFee = self.config.getint('Settings', 'addFee', fallback=1000)
            self.fontSize = self.config.getint('Settings', 'fontSize', fallback=14)
            self.weightInterval = self.config.getfloat('Settings', 'weightInterval', fallback=0.5)
            self.setSaveSetting = self.config.getboolean('Settings', 'setSaveSetting', fallback=False)
            self.favoriteDelv = self.config.get('Settings', 'favoriteDelv', fallback="노빠꾸해운(배송비)")
            self.use_kipris = self.config.getboolean('Kipris', 'use_Kipris', fallback=False)
            self.usage_mode = self.config.get('Kipris', 'usage_mode', fallback="web")
            self.api_key = self.config.get('Kipris', 'api_key', fallback="")

            print(f"use_kipris : {self.use_kipris}, usage_mode : {self.usage_mode}, api_key : {self.api_key}")
        except Exception as e:
            logger.error(f"설정을 불러오는 중 오류가 발생했습니다: {e}", exc_info=True)

    def saveSettings(self):
        """ 설정을 config.ini 파일에 저장합니다. """
        try:
            if not self.config.has_section('Settings'):
                self.config.add_section('Settings')
            
            self.config.set('Settings', 'maxWeightSet', str(self.maxWeightSet))
            self.config.set('Settings', 'maxLengthSet', str(self.maxLengthSet))
            self.config.set('Settings', 'maxVolumeSet', str(self.maxVolumeSet))
            self.config.set('Settings', 'addFeeInterval', str(self.addFeeInterval))
            self.config.set('Settings', 'addFeeSetting', str(self.addFeeSetting))
            self.config.set('Settings', 'addFee', str(self.addFee))
            self.config.set('Settings', 'fontSize', str(self.fontSize))
            self.config.set('Settings', 'weightInterval', str(self.weightInterval))
            self.config.set('Settings', 'setSaveSetting', str(self.setSaveSetting))
            self.config.set('Settings', 'favoriteDelv', str(self.favoriteDelv))

            if not self.config.has_section('Kipris'):
                self.config.add_section('Kipris')
            
            self.config.set('Kipris', 'use_kipris', str(self.use_kipris))
            self.config.set('Kipris', 'usage_mode', str(self.usage_mode))
            self.config.set('Kipris', 'api_key', str(self.api_key))

            with open(self.config_path, 'w') as configfile:
                self.config.write(configfile)
        except Exception as e:
            logger.error(f"설정을 저장하는 중 오류가 발생했습니다: {e}", exc_info=True)


    def create_default_settings(self):
        """ 기본 설정을 생성합니다. """
        self.config['Settings'] = {
            'maxWeightSet': '25',
            'maxLengthSet': '100',
            'maxVolumeSet': '160',
            'addFeeInterval': '5',
            'addFeeSetting': '20',
            'addFee': '1000',
            'fontSize': '14',
            'weightInterval': '0.5',
            'setSaveSetting': 'False',
            'favoriteDelv': "노빠꾸해운(배송비)",
        }
        self.config['Kipris'] = {
            'use_kipris': 'False',
            'usage_mode': 'web',
            'api_key': '',
        }

        with open(self.config_path, 'w') as configfile:
            self.config.write(configfile)

    def add_history(self, keyword) :
        if keyword:
            if keyword and keyword not in self.history:  # 중복된 검색어가 아니면 추가
                self.history.append(keyword)
                print(f"검색어 [{keyword}] 히스토리에 추가")

    def load_history(self):
        try:
            with open("search_history.json", "r") as file:
                self.history = json.load(file)
                print(f"self.history file loaded{self.history}")

        except (FileNotFoundError, json.JSONDecodeError):
            self.history = []
            print(f"self.history{self.history}")

    def save_history(self):
        with open("search_history.json", "w") as file:
            json.dump(self.history, file)
            
    def show_history_menu(self, event):
        if self.history:
            menu = QtWidgets.QMenu(self)
            for keyword in self.history:
                menu.addAction(keyword, lambda k=keyword: self.kipris_edit.setText(k))
            menu.exec_(self.kipris_edit.mapToGlobal(event.pos()))

    def closeEvent(self, event):
        # 설정 저장 여부 로그 기록
        if self.setSaveSetting:
            logger.debug("설정값 저장")
            self.saveSettings()  # 설정 저장
            # self.saveWindowSettings()  # 필요한 경우 윈도우 설정 저장
        else:
            logger.debug("설정값 저장하지 않음")

        # 검색 히스토리 저장
        self.save_history()

        # 부모 클래스의 종료 이벤트 처리 호출
        super().closeEvent(event)

        # 이벤트 처리 완료를 알림
        event.accept()

    def initUI(self):
        self.resize(300, 600)  # 창 크기 조정
        self.center()

        # 메뉴바 생성
        menubar = QtWidgets.QMenuBar(self)
        helpMenu = menubar.addMenu('도움말')
        kiprisMenu = menubar.addMenu('키프리스')

        # 도움말 - 도움말 보기 메뉴 아이템
        helpnemu_helpAction = QtWidgets.QAction('도움말 보기', self)
        helpnemu_helpAction.triggered.connect(self.showHelp)
        helpMenu.addAction(helpnemu_helpAction)
        # 도움말 - ChangeLog 메뉴 아이템
        helpnemu_changelogAction = QtWidgets.QAction('ChangeLog', self)
        helpnemu_changelogAction.triggered.connect(self.showChangeLog)
        helpMenu.addAction(helpnemu_changelogAction)
        # 도움말 - 기본값 설정 메뉴 아이템
        helpnemu_defaultAction = QtWidgets.QAction('기본값 설정', self)
        helpnemu_defaultAction.triggered.connect(self.setttingTosetDefaultValues)
        helpMenu.addAction(helpnemu_defaultAction)

        # # '설정창 열기' 메뉴 아이템
        openSettingsAction = QtWidgets.QAction('설정창 열기', self)
        openSettingsAction.triggered.connect(self.showSettingsDialog)
        kiprisMenu.addAction(openSettingsAction)
    



        # # 키프리스 - APIKEY 메뉴 아이템
        # kiprismenu_settingAction = QtWidgets.QAction('키프리스 ', self)
        # kiprismenu_settingAction.triggered.connect(self.showHelp)
        # kiprisMenu.addAction(kiprismenu_settingAction)
        # # 도움말 - ChangeLog 메뉴 아이템
        # changelogAction = QtWidgets.QAction('ChangeLog', self)
        # changelogAction.triggered.connect(self.showChangeLog)
        # kiprisMenu.addAction(changelogAction)
        # # 도움말 - 기본값 설정 메뉴 아이템
        # defaultAction = QtWidgets.QAction('기본값 설정', self)
        # defaultAction.triggered.connect(self.setttingTosetDefaultValues)
        # kiprisMenu.addAction(defaultAction)




        # 레이아웃 전체 설정
        self.layout = QtWidgets.QVBoxLayout(self)
        self.layout.setMenuBar(menubar)

        # 사용자 인터페이스 프레임
        self.user_frame = QtWidgets.QFrame(self)
        self.user_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.user_frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.user_layout = QtWidgets.QVBoxLayout(self.user_frame)

        # 콤보박스 초기화
        self.comboBox = QtWidgets.QComboBox()
        self.comboBox.currentIndexChanged.connect(self.updateComboBox)  # 값이 변경될 때 이벤트 연결
        self.user_layout.addWidget(self.comboBox)

        # 무게입력 박스 초기화
        self.weightInput = QtWidgets.QDoubleSpinBox()
        self.weightInput.setMinimum(0.5)
        self.weightInput.setMaximum(1000)
        self.weightInput.setSingleStep(self.weightInterval)
        self.weightInput.setSuffix(" Kg")
        self.weightInput.valueChanged.connect(self.updateDeliveryFee)  # 값이 변경될 때 이벤트 연결

        self.user_layout.addWidget(self.weightInput)

        # 부피 입력 칸: 가로, 세로, 높이
        self.dimension_layout = QtWidgets.QHBoxLayout()

        # 길이 레이아웃
        self.lengthInput = QtWidgets.QSpinBox()
        self.lengthInput.setMinimum(1)
        self.lengthInput.setMaximum(10000)
        self.lengthInput.setSuffix(" cm")
        self.lengthInput.valueChanged.connect(self.updateVolume)
        self.lengthInput_layout = self.create_label_and_spin_in_QV("가로(cm):", self.lengthInput)
        self.dimension_layout.addLayout(self.lengthInput_layout)

        # 넓이 레이아웃
        self.widthInput = QtWidgets.QSpinBox()
        self.widthInput.setMinimum(1)
        self.widthInput.setMaximum(10000)
        self.widthInput.setSuffix(" cm")
        self.widthInput.valueChanged.connect(self.updateVolume)
        self.widthInput_layout = self.create_label_and_spin_in_QV("세로(cm):", self.widthInput)
        self.dimension_layout.addLayout(self.widthInput_layout)

        # 높이 레이아웃
        self.heightInput = QtWidgets.QSpinBox()
        self.heightInput.setMinimum(1)
        self.heightInput.setMaximum(10000)
        self.heightInput.setSuffix(" cm")
        self.heightInput.valueChanged.connect(self.updateVolume)
        self.heightInput_layout = self.create_label_and_spin_in_QV("높이(cm):", self.heightInput)
        self.dimension_layout.addLayout(self.heightInput_layout)

        # 리셋 레이아웃
        self.reset_layout = QtWidgets.QVBoxLayout()

        self.reset_label = QtWidgets.QLabel("리셋")
        self.reset_layout.addWidget(self.reset_label)

        self.reset_button = QtWidgets.QPushButton("Reset")
        self.reset_label.setAlignment(QtCore.Qt.AlignCenter)
        self.reset_button.clicked.connect(self.reset_action)
        self.reset_layout.addWidget(self.reset_button)
        self.dimension_layout.addLayout(self.reset_layout)

        self.user_layout.addLayout(self.dimension_layout)

        # 레이아웃 비율 설정
        self.dimension_layout.setStretch(0, 3)  # 길이 입력 칸
        self.dimension_layout.setStretch(1, 3)  # 너비 입력 칸
        self.dimension_layout.setStretch(2, 3)  # 높이 입력 칸
        self.dimension_layout.setStretch(3, 1)  # 새로 추가된 리셋 레이아웃


        # 사용자 정보 프레임
        self.user_info_frame = QtWidgets.QFrame(self)
        self.user_info_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.user_info_frame.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.user_info_layout = QtWidgets.QVBoxLayout(self.user_info_frame)


        # 배송비 레이이웃 추가 설정 중
        self.final_delv_fee_layout = QtWidgets.QHBoxLayout()
        self.deliveryFeeLabel = QtWidgets.QLabel("배송비: 정보 없음")
        self.deliveryFeeADDLabel = QtWidgets.QLabel(f"가중치: {self.addFee}원")
        self.deliveryFeeADDLabel.setVisible(False)
        self.final_delv_fee_layout.addWidget(self.deliveryFeeLabel)
        self.final_delv_fee_layout.addWidget(self.deliveryFeeADDLabel)
        self.user_info_layout.addLayout(self.final_delv_fee_layout)

        # 부피 라벨
        self.volumeLabel = QtWidgets.QLabel("부피무게: 정보 없음")
        self.user_info_layout.addWidget(self.volumeLabel)

        # 크기 라벨
        self.maxLengthLabel = QtWidgets.QLabel("한 변의 최대길이 : 정보없음")
        self.maxLengthLabel.setVisible(False)
        self.user_info_layout.addWidget(self.maxLengthLabel)

        # 추가운임 정보 라벨
        self.additionalFeeTextLabel = QtWidgets.QLabel("화물택배(경동)추가운임 발생. 모든값은 참고치입니다.")
        self.additionalFeeTextLabel.setVisible(False)
        self.user_info_layout.addWidget(self.additionalFeeTextLabel)

        # 추가운임 라벨
        self.additionalFeeLabel = QtWidgets.QLabel("화물택배(경동)추가운임")
        self.additionalFeeLabel.setVisible(False)
        self.user_info_layout.addWidget(self.additionalFeeLabel)

        # 설정 프레임
        self.setting_frame = QtWidgets.QFrame(self)
        self.setting_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.setting_frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.setting_layout = QtWidgets.QVBoxLayout(self.setting_frame)

        # 폰트 크기 설정 스핀박스
        self.font_size_spinbox = QtWidgets.QSpinBox()
        self.font_size_spinbox.setRange(10, 50)
        self.font_size_spinbox.setValue(self.fontSize)
        self.font_size_spinbox.valueChanged.connect(self.setFontSize)
        self.font_size_spinbox_layout = self.create_label_and_spin("폰트 크기", self.font_size_spinbox)
        self.setting_layout.addLayout(self.font_size_spinbox_layout)

        # 스텝 간격 조정 스핀박스
        self.step_interval_spinbox = QtWidgets.QDoubleSpinBox()
        self.step_interval_spinbox.setRange(0.5, 10)
        self.step_interval_spinbox.setSingleStep(0.5)
        self.step_interval_spinbox.setValue(0.5)
        self.step_interval_spinbox.setSuffix(" Kg")
        self.step_interval_spinbox.valueChanged.connect(self.setStepInterval)
        self.step_interval_spinbox_layout = self.create_label_and_spin("무게 간격", self.step_interval_spinbox)
        self.setting_layout.addLayout(self.step_interval_spinbox_layout)

        # 경동택배 기준설정
        self.cargo_Layout = QtWidgets.QHBoxLayout()
        self.cargoLabel_upper = QtWidgets.QLabel()
        self.cargoLabel = QtWidgets.QLabel()
        self.cargoLabel_bottom = QtWidgets.QLabel()
        self.cargoLabel.setText("경동택배 설정")
        self.cargoLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.cargo_font.setPointSize(self.cargo_font_size)  # 폰트 크기를 16포인트로 설정
        self.cargoLabel.setFont(self.cargo_font)

        self.cargoLabel.setStyleSheet("background-color: lightgrey;")

        self.cargo_Layout.addWidget(self.cargoLabel_upper)
        self.cargo_Layout.addWidget(self.cargoLabel)
        self.cargo_Layout.addWidget(self.cargoLabel_bottom)
        self.setting_layout.addLayout(self.cargo_Layout)

        # 경동택배 길이기준 조정 스핀박스
        self.maxLength_spinbox = QtWidgets.QSpinBox()
        self.maxLength_spinbox.setRange(80, 200)
        self.maxLength_spinbox.setSingleStep(5)
        self.maxLength_spinbox.setValue(100)
        self.maxLength_spinbox.setSuffix(" cm")
        self.maxLength_spinbox.valueChanged.connect(self.setMaxLength)
        self.maxLength_spinbox_layout = self.create_label_and_spin("경동한변길이 설정", self.maxLength_spinbox)
        self.setting_layout.addLayout(self.maxLength_spinbox_layout)

        # 경동택배 부피기준 조정 스핀박스
        self.maxVolume_spinbox = QtWidgets.QSpinBox()
        self.maxVolume_spinbox.setRange(140, 200)
        self.maxVolume_spinbox.setSingleStep(5)
        self.maxVolume_spinbox.setValue(160)
        self.maxVolume_spinbox.setSuffix(" cm")
        self.maxVolume_spinbox.valueChanged.connect(self.setMaxVolume)
        self.maxVolume_spinbox_layout = self.create_label_and_spin("경동(세변합)기준 설정", self.maxVolume_spinbox)
        self.setting_layout.addLayout(self.maxVolume_spinbox_layout)
        
        # 경동택배 무게기준 조정 스핀박스
        self.maxWeight_spinbox = QtWidgets.QSpinBox()
        self.maxWeight_spinbox.setRange(10, 50)
        self.maxWeight_spinbox.setSingleStep(1)
        self.maxWeight_spinbox.setValue(25)
        self.maxWeight_spinbox.setSuffix(" Kg")
        self.maxWeight_spinbox.valueChanged.connect(self.setMaxWeight)
        self.maxWeight_spinbox_layout = self.create_label_and_spin("경동무게기준 설정", self.maxWeight_spinbox)
        self.setting_layout.addLayout(self.maxWeight_spinbox_layout)

        # 가중치 스핀박스
        self.addMoneySetlayout1 = QtWidgets.QHBoxLayout()
        self.addMoneySetlayout2 = QtWidgets.QHBoxLayout()
        self.addMoneySetlayout3 = QtWidgets.QHBoxLayout()
        self.label1 = QtWidgets.QLabel("가중치 기준")
        self.label2 = QtWidgets.QLabel(" 초과시 ")

        self.label3 = QtWidgets.QLabel(" 마다 ")

        self.label4 = QtWidgets.QLabel("추가")
        self.addMoney1_spinbox = QtWidgets.QSpinBox()
        self.addMoney1_spinbox.setRange(0, 1000)
        self.addMoney1_spinbox.setSingleStep(1)
        self.addMoney1_spinbox.setValue(20)
        self.addMoney1_spinbox.setSuffix(" Kg")
        self.addMoney1_spinbox.valueChanged.connect(self.setAddMoneySetting)
        self.addMoney2_spinbox = QtWidgets.QSpinBox()
        self.addMoney2_spinbox.setRange(0, 1000)
        self.addMoney2_spinbox.setSingleStep(1)
        self.addMoney2_spinbox.setValue(5)
        self.addMoney2_spinbox.setSuffix(" Kg")
        self.addMoney2_spinbox.valueChanged.connect(self.setAddInterval)
        self.addMoney3_spinbox = QtWidgets.QSpinBox()
        self.addMoney3_spinbox.setRange(0, 100000)
        self.addMoney3_spinbox.setSingleStep(1000)
        self.addMoney3_spinbox.setValue(1000)
        self.addMoney3_spinbox.setSuffix(" 원")
        self.addMoney3_spinbox.valueChanged.connect(self.setAddMoney)
        self.addMoneySetlayout1.addWidget(self.label1)
        self.addMoneySetlayout1.addWidget(self.addMoney1_spinbox)
        self.addMoneySetlayout2.addWidget(self.label2)
        self.addMoneySetlayout2.addWidget(self.addMoney2_spinbox)
        self.addMoneySetlayout3.addWidget(self.label3)
        self.addMoneySetlayout3.addWidget(self.label4)
        self.addMoneySetlayout3.addWidget(self.addMoney3_spinbox)
        self.addMoneySetlayout3.setStretch(0, 6)
        self.addMoneySetlayout3.setStretch(1, 2)
        self.addMoneySetlayout3.setStretch(2, 4)
        self.setting_layout.addLayout(self.addMoneySetlayout1)
        self.setting_layout.addLayout(self.addMoneySetlayout2)
        self.setting_layout.addLayout(self.addMoneySetlayout3)
  
        # 키프리스 프레임
        self.kiprisWidget = QtWidgets.QWidget(self)
        self.kipris_layout = QtWidgets.QHBoxLayout(self.kiprisWidget)
        self.kiprisWidget.setLayout(self.kipris_layout)
        self.kiprisWidget.setVisible(False)
        self.kipris_label = QtWidgets.QLabel("키프리스 검색")
        self.kipris_edit = QtWidgets.QLineEdit()
        self.kipris_btn = QtWidgets.QPushButton("검색")
        self.kipris_btn.clicked.connect(self.kipris_btn_clicked)
        self.kipris_edit.returnPressed.connect(self.kipris_btn_clicked)
        self.kipris_edit.mousePressEvent = self.show_history_menu
        self.kipris_layout.addWidget(self.kipris_label)
        self.kipris_layout.addWidget(self.kipris_edit)
        self.kipris_layout.addWidget(self.kipris_btn)
        self.kipris_layout.setStretch(0,3)
        self.kipris_layout.setStretch(1,6)
        self.kipris_layout.setStretch(2,3)
        # self.setting_layout.addLayout(self.kipris_layout)
        self.setting_layout.addWidget(self.kiprisWidget)  # self.kiprisWidget을 설정 레이아웃에 추가


        # 항상 위에 토글 스위치
        self.alwaysOnTopSwitch = ToggleSwitch(self.setting_frame)
        self.alwaysOnTopSwitch.move(10, 10)
        self.alwaysOnTopSwitch.setChecked(True)  # 기본 상태는 ON
        self.alwaysOnTopSwitch.clicked.connect(self.toggleAlwaysOnTop)
        self.alwaysOnTopSwitch_layout = self.create_label_and_switch("항상 위에 표시", self.alwaysOnTopSwitch)
        self.setting_layout.addLayout(self.alwaysOnTopSwitch_layout)  

        # 설정값 저장 토글 스위치
        self.saveSettingSwitch = ToggleSwitch(self.setting_frame)
        self.saveSettingSwitch.move(10, 10)
        self.saveSettingSwitch.setChecked(False)  # 기본 상태는 OFF
        self.saveSettingSwitch.clicked.connect(self.isSaveSetting)
        self.saveSettingSwitch_layout = self.create_label_and_switch("설정값 저장", self.saveSettingSwitch)
        self.setting_layout.addLayout(self.saveSettingSwitch_layout)

        # 낙인
        self.infoLabel4 = QtWidgets.QLabel("           배송비계산기 by 내차는언제타냐")
        self.setting_layout.addWidget(self.infoLabel4)

        # 레이아웃 비율 조정
        self.layout.addWidget(self.user_frame, 3)
        self.layout.addWidget(self.user_info_frame, 3)
        self.layout.addWidget(self.setting_frame, 4)

        self.setWindowTitle('배송비 계산기')

    def initSettings_for_kipris_ori(self):
        if self.kiprisAPI:
            # 현재 객체가 적절한 타입인지 확인
            current_type = type(self.kiprisAPI)
            target_type = Kipris_API if self.usage_mode == 'api' else Kipris_WEB
            
            if current_type is not target_type:
                # 기존 객체가 다른 타입이면 삭제하고 새로 생성
                print(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
                self.kiprisAPI.close_Kipris()  # 기존객체 리소스 정리
                del self.kiprisAPI  # 기존 객체 참조 제거
                self.kiprisAPI = target_type(self.api_key)  # 새 객체 생성
                print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
            else:
                print(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
        else:
            # 객체가 없으면 새로 생성
            self.kiprisAPI = Kipris_API(self.api_key) if self.usage_mode == 'api' else Kipris_WEB(self.api_key)
            print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")

    def initSettings_for_kipris(self):
        if self.kiprisAPI:
            # 현재 객체가 적절한 타입인지 확인
            current_type = type(self.kiprisAPI)
            target_type = Kipris_API if self.usage_mode == 'api' else AsyncWebSearchWorker
            
            if current_type is not target_type:
                # 기존 객체가 다른 타입이면 삭제하고 새로 생성
                print(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.")
                if isinstance(self.kiprisAPI, AsyncWebSearchWorker):
                    self.kiprisAPI.deleteLater()  # 비동기 작업자는 Qt 객체로 관리되므로 deleteLater 사용
                self.kiprisAPI = None
                if self.usage_mode == 'api':
                    self.kiprisAPI = Kipris_API(self.api_key)  # 새 객체 생성
                else:
                    web_scraper = WebScraper()  # WebScraper 인스턴스 생성
                    self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "")  # 초기 키워드는 비워두기
                print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")
            else:
                print(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.")
        else:
            # 객체가 없으면 새로 생성
            if self.usage_mode == 'api':
                self.kiprisAPI = Kipris_API(self.api_key)
            else:
                web_scraper = WebScraper()  # WebScraper 인스턴스 생성
                self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "")  # 초기 키워드는 비워두기
            print(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}")


    def showSettingsDialog(self):
        if self.settingDialog.exec_():
            self.use_kipris = self.settingDialog.use_kipris
            self.usage_mode = self.settingDialog.usage_mode
            self.api_key = self.settingDialog.api_key

            self.kipris_Visible()

    def kipris_Visible(self):
        if self.use_kipris:
            self.kiprisWidget.setVisible(True)
            self.initSettings_for_kipris()
        else:
            self.kiprisWidget.setVisible(False)

    def create_label_and_switch(self, label_text, target_switch):
        layout = QtWidgets.QHBoxLayout()
        label = QtWidgets.QLabel(label_text)
        # label.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(label)
        layout.addWidget(target_switch)
        return layout

    def create_label_and_spin(self, label_text, spin):
        layout = QtWidgets.QHBoxLayout()
        label = QtWidgets.QLabel(label_text)
        # label.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(label)
        layout.addWidget(spin)
        return layout

    def create_label_and_spin_in_QV(self, label_text, spin):
        layout = QtWidgets.QVBoxLayout()
        label = QtWidgets.QLabel(label_text)
        label.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(label)
        layout.addWidget(spin)
        return layout

    def center(self):
        qr = self.frameGeometry()
        cp = QtWidgets.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def loadDeliveryFees(self):
        try:
            excel_file = pd.ExcelFile('delv.xlsx')
            sheets = excel_file.sheet_names
            for sheet in sheets:
                df = excel_file.parse(sheet)
                # 시트 내 컬럼 확인 및 데이터 처리
                if '무게' in df.columns and '배송비' in df.columns:
                    self.processSheet(df, sheet, '무게')
                if '부피' in df.columns and '배송비' in df.columns:
                    self.processSheet(df, sheet, '부피')
                    
                if sheet.endswith('(배송비)'):
                    self.comboBox.addItem(sheet)

            logger.debug('Excel file loaded successfully.')
        except Exception as e:
            logger.error(f"Error loading Excel file: {e}", exc_info=True)
            QtWidgets.QMessageBox.critical(self, "Error", "Failed to load the Excel file.")

    def processSheet(self, df, sheet_name, key):
        records = []
        for index, row in df.iterrows():
            try:
                value_str = re.findall(r'\d+[\d,]*', str(row[key]))[0].replace(',', '')
                fee_str = re.findall(r'\d+[\d,]*', str(row['배송비']))[0].replace(',', '')
                value = float(value_str)
                fee = int(fee_str)
                records.append({key: value, '배송비': fee})
            except ValueError as e:
                logger.error(f"Error converting values in row {index} of sheet {sheet_name}: {e}")
                continue
        self.deliveryFees[sheet_name] = records

    def setDefaultValues(self):
        self.weightInput.setValue(1)
        self.widthInput.setValue(1)
        self.lengthInput.setValue(1)
        self.heightInput.setValue(1)

        self.updateDeliveryFee()

    def updateDeliveryFee(self):
        try:
            weight = self.weightInput.value()
            # logger.debug(f"현재 선택된 무게 : {weight}")
            selected_sheet = self.comboBox.currentText()
            # logger.debug(f"현재 선택된 시트 : {selected_sheet}")
            fees = self.deliveryFees.get(selected_sheet, [])
            fee = 0
            # 가능한 모든 무게를 리스트로 가져오고 정렬
            sorted_fees = sorted((float(f['무게']), int(f['배송비'])) for f in fees if '무게' in f and '배송비' in f)

            # 입력된 무게보다 작거나 같은 최대 무게 찾기
            closest_fee = None
            for w, f in sorted_fees:
                if weight >= w:
                    closest_fee = f
                else:
                    break

            # 배송비 업데이트
            if closest_fee is not None:
                fee = closest_fee

            # 추가 배송비 계산
            if weight > self.addFeeSetting:
                # 추가될 배송비 횟수 계산
                additional_fee_count = (weight - self.addFeeSetting) // self.addFeeInterval
                if (weight - self.addFeeSetting) % self.addFeeInterval != 0:
                    additional_fee_count += 1
                total_add_fee = additional_fee_count * self.addFee
                fee += total_add_fee
                self.deliveryFeeLabel.setText(f'배송비: {int(fee): ,}원 (추가 배송비 {int(total_add_fee)} 포함)')
            else:
                self.deliveryFeeLabel.setText(f'배송비: {int(fee): ,}원')

            # logger.debug(f"배송비 deliveryFeeLabel에 업데이트: {int(fee): ,}원")

            # 폰트와 밑줄 설정
            font = QFont()
            font.setBold(True)  # 굵게
            font.setUnderline(True)  # 밑줄
            self.deliveryFeeLabel.setFont(font)

            self.currentWeight = weight
            self.additionalFee()

        except Exception as e:
            logger.error(f"Error updating delivery fee: {e}", exc_info=True)
            self.deliveryFeeLabel.setText("배송비 업데이트 중 오류 발생")

    def updateAdditionalDeliveryFee(self):
        try:
            weight = self.weightInput.value()
            volume = self.currentVolume  # 현재 부피
            logger.debug(f"현재 선택된 무게 : {weight}")
            selected_v_sheet = '경동부피'
            selected_w_sheet = '경동무게'
            v_fees = self.deliveryFees.get(selected_v_sheet, [])
            w_fees = self.deliveryFees.get(selected_w_sheet, [])
            # 가능한 모든 무게를 리스트로 가져오고 정렬
            sorted_v_fees = sorted((float(f['부피']), int(f['배송비'])) for f in v_fees if '부피' in f and '배송비' in f)
            sorted_w_fees = sorted((float(f['무게']), int(f['배송비'])) for f in w_fees if '무게' in f and '배송비' in f)
            # logger.debug(f"경동부피무게 가격 : {sorted_v_fees}")
            # logger.debug(f"경동무게당  가격 : {sorted_w_fees}")

            # 입력된 무게보다 작거나 같은 최대 무게 찾기
            closest_v_fee = None
            closest_w_fee = None
            price_source = ""

            # 무게에 따른 최적 배송비 계산
            for w_w, w_f in sorted_w_fees:
                if weight >= w_w:
                    closest_w_fee = w_f
                else:
                    break

            # 부피에 따른 최적 배송비 계산
            for v_w, v_f in sorted_v_fees:
                if volume >= v_w:
                    closest_v_fee = v_f
                else:
                    break

            # 최종 가격 결정 및 가격 출처 확인
            if closest_v_fee is not None and closest_w_fee is not None:
                if closest_v_fee >= closest_w_fee:
                    closest_final_fee = closest_v_fee
                    price_source = "부피"
                else:
                    closest_final_fee = closest_w_fee
                    price_source = "무게"
            elif closest_v_fee is not None:
                closest_final_fee = closest_v_fee
                price_source = "부피"
            elif closest_w_fee is not None:
                closest_final_fee = closest_w_fee
                price_source = "무게"
            else:
                closest_final_fee = 0
                price_source = "데이터 없음"

            # 폰트와 밑줄 설정
            font = QFont()
            font.setBold(True)  # 굵게
            font.setUnderline(True)  # 밑줄
            self.additionalFeeLabel.setFont(font)

            # 배송비 업데이트 및 라벨 표시
            fee = f"{closest_final_fee: ,}원"
            self.additionalFeeLabel.setText(f'경동 택배비[{price_source}]: {fee}')

        except Exception as e:
            logger.error(f"Error updating Additional delivery fee: {e}", exc_info=True)
            self.additionalFeeLabel.setText("배송비 업데이트 중 오류 발생")


    def updateComboBox(self):
        selected_Delv = self.comboBox.currentText()
        logger.debug(f"선택된 배대지: {selected_Delv}")
        self.favoriteDelv = selected_Delv
        self.updateDeliveryFee()

    def setComboBox(self):
        logger.debug(f"self.favoriteDelv: {self.favoriteDelv}")

        if self.favoriteDelv:
            index = self.comboBox.findText(self.favoriteDelv)
            logger.debug(f"저장된 배대지가 존재함: {self.favoriteDelv}")
            if index >= 0:
                self.comboBox.setCurrentIndex(index)
        else:
            logger.debug("저장된 배대지가 엑셀시트에 존재하지 않습니다.")


    def additionalFee(self):
        messages = []
        exceeded = False

        if self.currentWeight >= self.maxWeightSet:
            messages.append(f"무게기준 [{self.maxWeightSet}Kg] 초과")
            exceeded = True
        if self.currentMaxLength >= self.maxLengthSet:
            messages.append(f"길이기준 [{self.maxLengthSet}cm] 초과")
            exceeded = True
        if self.roundVolume >= self.maxVolumeSet:
            logger.debug(f"self.roundVolume : {self.roundVolume}")
            logger.debug(f"maxVolumeSet : {self.maxVolumeSet}")
            messages.append(f"세변의 합 기준 [{self.maxVolumeSet}cm] 초과")
            exceeded = True

        if exceeded:
            # 모든 메시지를 연결하여 표시
            self.additionalFeeTextLabel.setText(", ".join(messages))
            self.additionalFeeLabel.setVisible(True)
            self.additionalFeeTextLabel.setVisible(True)
            self.updateAdditionalDeliveryFee()
        else:
            self.additionalFeeLabel.setVisible(False)
            self.additionalFeeTextLabel.setVisible(False)


    def updateVolume(self):
        length = self.lengthInput.value()
        width = self.widthInput.value()
        height = self.heightInput.value()


        volume = length * width * height
        roundVolume = length + width + height
        self.currentVolume = volume
        self.roundVolume = roundVolume
        self.volumeLabel.setText(f"부피: {volume: ,} cm³")

        self.currentMaxLength = max(length,width,height)
        if self.currentMaxLength > self.maxLengthSet:
            self.maxLengthLabel.setText(f"한 변의 최대길이 : {self.currentMaxLength}cm")
            self.maxLengthLabel.setVisible(True)
        else:
            self.maxLengthLabel.setVisible(False)
        self.additionalFee()

    def toggleAlwaysOnTop(self, state):
        if state:
            self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
        else:
            self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint)
        self.show()  # 변경된 윈도우 플래그를 적용하기 위해 위젯을 다시 보여줘야 함

    def setFontSize(self, value):
        font = self.font()
        font.setPointSize(value)
        self.setFont(font)
        self.fontSize = value
        self.cargo_font.setPointSize(self.cargo_font_size)

    def setStepInterval(self, value):
        self.weightInput.setSingleStep(value)
        self.weightInterval = value

    def setMaxWeight(self, value):
        self.maxWeightSet = value
        self.updateDeliveryFee()

    def setMaxLength(self, value):
        self.maxLengthSet = value
        self.updateDeliveryFee()

    def setMaxVolume(self, value):
        self.maxVolumeSet = value
        self.updateDeliveryFee()

    def setAddMoneySetting(self, value):
        self.addFeeSetting = value
        if self.addFeeSetting == 0:
            self.addFee = 2000
        self.updateDeliveryFee()

    def setAddMoney(self, value):
        self.addFee = value
        self.updateDeliveryFee()

    def setAddInterval(self, value):
        self.addFeeInterval = value
        self.updateDeliveryFee()

    def isSaveSetting(self, state):
        if state:
            self.setSaveSetting = True
        else:
            self.setSaveSetting = False

        logger.debug(f"설정값 저장세팅 : {self.setSaveSetting}")
        self.show()

    def kipris_btn_clicked(self):
        self.search_keyword = self.kipris_edit.text()
        logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{self.search_keyword}]")

        # result = self.kiprisAPI.run(self.search_keyword, self.set_status)
        # print(f"result {result}")

        if self.search_keyword.strip():  # 검색어가 비어있지 않은 경우에만 검색 수행
            self.handle_search_for_web(self.search_keyword)

    def handle_search_for_web(self, keyword):
        self.add_history(keyword)  # 검색어 히스토리 추가
        if self.asyncWorker:  # 기존에 비동기 작업자가 존재한다면
            self.asyncWorker.thread.quit()  # 기존 스레드 종료

        print(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")
        self.asyncWorker = AsyncWebSearchWorker(keyword, self.set_status)  # 새 비동기 작업자 생성
        self.asyncWorker.finished.connect(self.display_results_for_web)  # 완료 시그널을 결과 표시 함수에 연결
        self.asyncWorker.start()  # 비동기 작업 시작
        print("비동기 검색 시작")

    def display_results_for_web(self, result, elapsed_time):
        message = f"검색 결과 : {result}\n검색에 걸린 시간: {elapsed_time:.1f}초"
        QtWidgets.QMessageBox.information(self, "Search Results", message)

        self.asyncWorker = None  # 작업 완료 후 객체 참조 해제

    def handle_search_for_api(self, keyword):
        self.add_history(keyword)
        
        if self.searchThread is not None and self.searchThread.isRunning():
            self.searchThread.quit()  # 이전 스레드가 실행 중이라면 안전하게 종료
            print("기존 쓰레드가 존재하므로 기존 쓰레드 종료")
        print(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]")

        worker = APISearchWorker(self.kiprisAPI, keyword, self.set_status)

        # worker = SearchWorker(self.kiprisAPI, keyword, self.set_status)

        print("워커 생성")
        self.searchThread = SearchThread(worker)
        print("쓰레드 생성")
        worker.finished.connect(self.display_results)
        self.searchThread.finished.connect(self.clear_thread_reference)
        self.searchThread.start_search()
        print("검색 시작")

    def clear_thread_reference(self):
        # 스레드 종료 후 참조를 제거하여 다음 검색을 위해 준비
        self.searchThread = None

    def display_results(self, result, elapsed_time):
        message = f"검색 결과 : {result}\n검색에 걸린 시간: {elapsed_time:.1f}초"
        QtWidgets.QMessageBox.information(self, "Search Results", message)

    def reset_action(self):
        self.lengthInput.setValue(1)
        self.widthInput.setValue(1)
        self.heightInput.setValue(1)

    def showHelp(self):
        # 도움말 내용 표시
        helpText = "안녕하세요 내차는 언제타냐 입니다. \n - 모든 입력칸에는 마우스 휠로 입력가능하고, \n - 컨트롤+휠 동작시 (기본값x10) 값으로 변경가능합니다.\n - 배대지를 추가하려면 첨부된 엑셀파일 delv.xlsx를 참조하세요 \n - 배대지 순서를 정하려면 시트이름에 번호를 붙이세요."
        QtWidgets.QMessageBox.information(self, '도움말', helpText)

    def showChangeLog(self):
        # ChangeLog 내용 표시
        QtWidgets.QMessageBox.information(self, 'ChangeLog', "Version 1.0 \n Inintial Launch\n\nVersion 1.0.1 \n Dimension에 Reset버튼 추가")

    def setttingTosetDefaultValues(self):
        # 기본값 설정 로직
        QtWidgets.QMessageBox.information(self, '기본값 설정', "기본값으로 설정합니다.")
        self.font_size_spinbox.setValue(14)
        # self.setFontSize
        self.addMoney1_spinbox.setValue(20)
        self.addMoney2_spinbox.setValue(5)
        self.addMoney3_spinbox.setValue(5000)
        self.saveSettingSwitch.setChecked(False)
        self.step_interval_spinbox.setValue(0.5)
        self.maxVolume_spinbox.setValue(160)
        self.maxWeight_spinbox.setValue(25)
        self.maxLength_spinbox.setValue(100)

        self.favoriteDelv = None
        self.setComboBox()

if __name__ == '__main__':
    minimize_console()

    app = QtWidgets.QApplication(sys.argv)
    logger = setup_logger('default_logger', 'delivery_calc.log', level=logging.INFO)
    ex = DeliveryFeeCalculator(logger)
    ex.show()
    sys.exit(app.exec_())
