from PySide6.QtCore import QSettings
import logging

class SettingsManager:
    """
    사용자 설정값(토글, 스핀, 텍스트 등)을 저장/불러오고,
    각종 위젯에 따라 UI 상태까지 자동 적용하는 매니저 클래스입니다.
    """

    def __init__(self, logger=None, organization="WhenRideMycar", application="EditPartTimer3"):
        """
        QSettings 기반 설정 매니저 초기화

        :param logger: logging.Logger 또는 print 대체용 함수
        :param organization: QSettings 구분용 회사명
        :param application: QSettings 구분용 앱명
        """
        self.logger = logger or logging.getLogger(__name__)
        self.settings = QSettings(organization, application)
        self.widget_map = {}          # 위젯명 → 저장키 매핑
        self.toggle_dependencies = {} # 토글명 → 종속 위젯 매핑

    def _log(self, message, level=logging.INFO):
        """
        커스텀/표준 로거 모두 지원하는 내부 로깅 함수
        """
        if hasattr(self.logger, "log") and "level" in self.logger.log.__code__.co_varnames:
            # 커스텀 로거: self.logger.log(msg, level=logging.INFO)
            self.logger.log(message, level=level)
        else:
            # 표준 로거
            if level == logging.DEBUG:
                self.logger.debug(message)
            elif level == logging.INFO:
                self.logger.info(message)
            elif level == logging.WARNING:
                self.logger.warning(message)
            elif level == logging.ERROR:
                self.logger.error(message)
            elif level == logging.CRITICAL:
                self.logger.critical(message)
            else:
                self.logger.info(message)

    def bind_widgets(self, widget_map, toggle_dependencies):
        """
        위젯-키, 토글-종속 딕셔너리를 등록합니다.
        :param widget_map: { "widget명": "저장키" }
        :param toggle_dependencies: { "toggle명": { "dependents": [...], "visible": [...] } }
        """
        self.widget_map = widget_map
        self.toggle_dependencies = toggle_dependencies

    def save_settings(self, widget_obj):
        """
        현재 UI에 연결된 각종 위젯의 값을 QSettings에 저장합니다.

        :param widget_obj: 실제 위젯 객체(self 등)

        config 예시:
        {
            'discord_notify_toggle': {
                'dependents': ['webhook_input'],
                'visible': ['webhook_input'],
            },
            'ocr_toggle': {
                'dependents': ['unwanted_words_button']
            },
            ...
        }
        """
        for widget_name, key in self.widget_map.items():
            widget = getattr(widget_obj, widget_name, None)
            if widget is None:
                self._log(f"[SettingsManager] '{widget_name}' 위젯을 찾을 수 없습니다.", logging.WARNING)

                continue

            try:
                # 체크박스, 토글, 커스텀토글 등
                if hasattr(widget, 'isChecked'):
                    value = bool(widget.isChecked())
                    self.logger.log(f"[SettingsManager] bool 타입 저장: {key} 값 저장: {value}", level=logging.DEBUG)
                    self.settings.setValue(key, value)
                # SpinBox/DoubleSpinBox 등
                elif hasattr(widget, 'value'):
                    self.settings.setValue(key, widget.value())
                    self.logger.log(f"[SettingsManager] int/float 타입 저장: {key} 값 저장: {widget.value()}", level=logging.DEBUG)
                # QLineEdit 등 (단일줄 텍스트)
                elif hasattr(widget, 'text'):
                    self.settings.setValue(key, widget.text())
                    self.logger.log(f"[SettingsManager] str 타입 저장: {key} 값 저장: {widget.text()}", level=logging.DEBUG)
                # QTextEdit 등 (여러줄 텍스트)
                elif hasattr(widget, 'toPlainText'):
                    self.settings.setValue(key, widget.toPlainText())
                    self.logger.log(f"[SettingsManager] str 타입 저장: {key} 값 저장: {widget.toPlainText()}", level=logging.DEBUG)
                else:
                    self._log(f"[SettingsManager] '{widget_name}'의 값을 저장하는 방법을 알 수 없습니다.", logging.WARNING)

            except Exception as e:
                self._log(f"[SettingsManager] '{widget_name}' 저장 중 오류: {e}", logging.ERROR, exc_info=True)

    def save_value(self, key, value):
        """특정 키로 단일 값을 설정에 저장합니다. 타입별로 정확히 저장."""
        try:
            # bool
            if isinstance(value, bool):
                self.settings.setValue(key, value)
                self.logger.log(f"[SettingsManager] bool 타입 저장: {key} 값 저장: {value}", level=logging.DEBUG)
            # int/float
            elif isinstance(value, (int, float)):
                self.settings.setValue(key, value)
                self.logger.log(f"[SettingsManager] int/float 타입 저장: {key} 값 저장: {value}", level=logging.DEBUG)
            # 그 외(특히 str)
            else:
                self.settings.setValue(key, str(value))
                self.logger.log(f"[SettingsManager] str 타입 저장: {key} 값 저장: {value}", level=logging.DEBUG)
            self.settings.sync()
            self._log(f"[SettingsManager] {key} 값을 저장했습니다: {value}")
        except Exception as e:
            self._log(f"[SettingsManager] {key} 값 저장 중 오류: {e}", level=logging.WARNING)
        
    # 기타 값 직접 접근용
    def get_value(self, key, default=None):
        return self.settings.value(key, default)

    def load_settings(self, widget_obj):    
        """
        QSettings에서 저장된 값을 각 위젯에 복원합니다.

        :param widget_obj: 실제 위젯 객체(self 등)
        """
        for widget_name, key in self.widget_map.items():
            widget = getattr(widget_obj, widget_name, None)
            if widget is None:
                self._log(f"[SettingsManager] '{widget_name}' 위젯을 찾을 수 없습니다.", logging.WARNING)
                continue

            val = self.settings.value(key, None)
            if val is None:
                continue  # 미저장 값

            try:
                # 체크박스/토글 등 (bool 변환)
                if hasattr(widget, 'setChecked'):
                    # QSettings는 bool을 str로 저장할 수 있어 안전하게 변환
                    if isinstance(val, bool):
                        widget.setChecked(val)
                    elif isinstance(val, (int, float)):
                        widget.setChecked(bool(val))
                    elif isinstance(val, str):
                        widget.setChecked(val.lower() in ['true', '1', 'yes'])
                # SpinBox류
                elif hasattr(widget, 'setValue'):
                    if isinstance(val, (int, float)):
                        widget.setValue(val)
                    elif isinstance(val, str):
                        if '.' in val:
                            widget.setValue(float(val))
                        else:
                            widget.setValue(int(val))
                # QLineEdit 등
                elif hasattr(widget, 'setText'):
                    widget.setText(str(val))
                # QTextEdit 등
                elif hasattr(widget, 'setPlainText'):
                    widget.setPlainText(str(val))
                else:
                    self._log(f"[SettingsManager] '{widget_name}'에 값을 복원할 수 없습니다.", logging.WARNING)
            except Exception as e:
                self._log(f"[SettingsManager] '{widget_name}' 불러오기 오류: {e}", logging.ERROR, exc_info=True)

    def reset_settings(self):
        """
        전체 QSettings 값을 초기화(삭제)합니다.
        """
        try:
            self.settings.clear()
            self._log("[SettingsManager] 모든 설정이 초기화되었습니다.", logging.INFO)
        except Exception as e:
            self._log(f"[SettingsManager] 설정 초기화 실패: {e}", logging.ERROR, exc_info=True)

    def remove_setting(self, key):
        """
        특정 키의 설정만 삭제합니다.

        :param key: 삭제할 설정 키(str)
        """
        try:
            self.settings.remove(key)
            self._log(f"[SettingsManager] '{key}' 설정이 삭제되었습니다.", logging.INFO)
        except Exception as e:
            self._log(f"[SettingsManager] '{key}' 삭제 실패: {e}", logging.ERROR, exc_info=True)

    def debug_print(self):
        """
        QSettings에 저장된 모든 값을 로그로 출력합니다.
        """
        try:
            self.settings.sync()
            all_keys = self.settings.allKeys()
            self.logger.info("[SettingsManager] 저장된 모든 설정값:")
            for key in all_keys:
                value = self.settings.value(key)
                self.logger.info(f"  {key}: {value}")
        except Exception as e:
            self._log(f"[SettingsManager] 설정값 출력 실패: {e}", logging.ERROR, exc_info=True)

    def apply_settings_to_ui(self, widget_obj):
        """
        종속 딕셔너리(toggle_dependencies)에 따라,
        토글/체크박스 등 상태에 따라 dependents/visible 위젯을 자동으로 활성/비활성, 표시/숨김 처리합니다.

        :param widget_obj: 실제 위젯 객체(self 등)
        """
        for toggle_name, deps in self.toggle_dependencies.items():
            toggle_widget = getattr(widget_obj, toggle_name, None)
            if toggle_widget is None or not hasattr(toggle_widget, "isChecked"):
                continue
            checked = toggle_widget.isChecked()
            # 종속 위젯 enable/disable
            for dep in deps.get("dependents", []):
                dep_widget = getattr(widget_obj, dep, None)
                if dep_widget and hasattr(dep_widget, "setEnabled"):
                    try:
                        dep_widget.setEnabled(checked)
                    except Exception as e:
                        self._log(f"[SettingsManager] {dep} setEnabled 실패: {e}", logging.ERROR, exc_info=True)
            # 종속 위젯 visible
            for vis in deps.get("visible", []):
                vis_widget = getattr(widget_obj, vis, None)
                if vis_widget and hasattr(vis_widget, "setVisible"):
                    try:
                        vis_widget.setVisible(checked)
                    except Exception as e:
                        self._log(f"[SettingsManager] {vis} setVisible 실패: {e}", logging.ERROR, exc_info=True)

            # (필요 시) 확장: 토글에 따라 특정 값을 리셋, 콜백 트리거 등











    def save_user_info(self, user_info: dict):
        for key, value in user_info.items():
            self.settings.setValue(f"user/{key}", value)
        self.settings.sync()

    def load_user_info(self) -> dict:
        info = {}
        for key in ["email", "password", "id", "membership_level", "name"]:
            info[key] = self.settings.value(f"user/{key}", "")
        return info
    