import logging

from pypos.core.utils.ui_message_utils import sanitize_ui_message

LOGGER = logging.getLogger(__name__)


class BaseController:

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not hasattr(self, "view"):
            self.view = None
        self._disposed = False

    def set_view(self, view):
        self.view = view
        return self.view

    def bind_view(self, view, bind_back=True):
        self.set_view(view)
        if bind_back and hasattr(view, "set_controller"):
            try:
                view.set_controller(self)
            except (AttributeError, RuntimeError, TypeError):
                pass
        return view

    @property
    def is_disposed(self):
        return bool(getattr(self, "_disposed", False))

    def dispose(self):
        self._disposed = True
        return True

    def safe_call(self, callback, *args, default=None, on_error=None, reraise=False, **kwargs):
        try:
            return callback(*args, **kwargs)
        except Exception as exc:
            if callable(on_error):
                on_error(exc)
            if reraise:
                raise
            return default

    def _resolve_view_target(self, view=None):
        if view is not None:
            return view
        return getattr(self, "view", None)

    def _show_message_fallback(self, level, title, message, view=None):
        safe_message, sanitized = sanitize_ui_message(level, message)
        if sanitized:
            LOGGER.warning("UI message sanitized in %s: %s", self.__class__.__name__, message)
        try:
            from PySide6.QtWidgets import QMessageBox

            parent = self._resolve_view_target(view)
            safe_title = str(title or "Informasi")
            safe_message = str(safe_message or "")
            if level == "critical":
                QMessageBox.critical(parent, safe_title, safe_message)
            elif level == "warning":
                QMessageBox.warning(parent, safe_title, safe_message)
            else:
                QMessageBox.information(parent, safe_title, safe_message)
            return
        except (ImportError, ModuleNotFoundError, RuntimeError, TypeError):
            pass
        level_name = str(level or "information").lower()
        if level_name == "critical":
            LOGGER.error("[%s] %s", title, safe_message)
        elif level_name == "warning":
            LOGGER.warning("[%s] %s", title, safe_message)
        else:
            LOGGER.info("[%s] %s", title, safe_message)

    def show_warning(self, title, message=None, view=None):
        if message is None:
            message = title
            title = "Peringatan"
        safe_message, sanitized = sanitize_ui_message("warning", message)
        if sanitized:
            LOGGER.warning("UI warning sanitized in %s: %s", self.__class__.__name__, message)
        target = self._resolve_view_target(view)
        if target and hasattr(target, "show_warning"):
            try:
                target.show_warning(title, safe_message)
                return
            except (AttributeError, RuntimeError, TypeError):
                pass
        self._show_message_fallback("warning", title, safe_message, view=target)

    def show_info(self, title, message=None, view=None):
        if message is None:
            message = title
            title = "Informasi"
        safe_message, sanitized = sanitize_ui_message("information", message)
        if sanitized:
            LOGGER.warning("UI info sanitized in %s: %s", self.__class__.__name__, message)
        target = self._resolve_view_target(view)
        if target and hasattr(target, "show_info"):
            try:
                target.show_info(title, safe_message)
                return
            except (AttributeError, RuntimeError, TypeError):
                pass
        self._show_message_fallback("information", title, safe_message, view=target)

    def show_error(self, title, message=None, view=None):
        if message is None:
            message = title
            title = "Error"
        safe_message, sanitized = sanitize_ui_message("critical", message)
        if sanitized:
            LOGGER.warning("UI error sanitized in %s: %s", self.__class__.__name__, message)
        target = self._resolve_view_target(view)
        if target and hasattr(target, "show_error"):
            try:
                target.show_error(safe_message, title=title)
                return
            except (AttributeError, RuntimeError, TypeError):
                pass
        self._show_message_fallback("critical", title, safe_message, view=target)

    def ask_confirm(self, title, message, view=None, yes_label=None, no_label=None, default_no=True):
        target = self._resolve_view_target(view)
        has_custom_label = bool(yes_label or no_label)
        if target and not has_custom_label:
            if hasattr(target, "show_confirm"):
                try:
                    return bool(target.show_confirm(title, message))
                except (AttributeError, RuntimeError, TypeError):
                    pass
            if hasattr(target, "show_confirmation"):
                try:
                    return bool(target.show_confirmation(title, message))
                except (AttributeError, RuntimeError, TypeError):
                    pass
        try:
            from PySide6.QtWidgets import QMessageBox

            if has_custom_label:
                msg = QMessageBox(target)
                msg.setWindowTitle(str(title or "Konfirmasi"))
                msg.setText(str(message or ""))
                msg.setIcon(QMessageBox.Warning)
                yes_btn = msg.addButton(str(yes_label or "Ya"), QMessageBox.AcceptRole)
                msg.addButton(str(no_label or "Tidak"), QMessageBox.RejectRole)
                if default_no:
                    msg.setDefaultButton(QMessageBox.NoButton)
                msg.exec()
                return msg.clickedButton() == yes_btn

            reply = QMessageBox.question(
                target,
                str(title or "Konfirmasi"),
                str(message or ""),
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No if default_no else QMessageBox.Yes,
            )
            return reply == QMessageBox.Yes
        except (ImportError, ModuleNotFoundError, RuntimeError, TypeError):
            LOGGER.warning("Dialog konfirmasi fallback tanpa UI: [%s] %s", title, message)
            return False

    def _log(self, level, message):
        name = self.__class__.__name__
        safe_level = str(level or "INFO").upper()
        level_num = getattr(logging, safe_level, logging.INFO)
        LOGGER.log(level_num, "[%s] %s", name, message)

    def log_debug(self, message):
        self._log("DEBUG", message)

    def log_info(self, message):
        self._log("INFO", message)

    def log_warning(self, message):
        self._log("WARN", message)

    def log_error(self, message):
        self._log("ERROR", message)
