import logging
import re
from functools import wraps
from pathlib import Path

from PySide6.QtCore import QUrl

_MANGLED_DRIVE_RE = re.compile(r"^/([A-Za-z]:)")


def to_local_path(path_or_url: str) -> Path:
    """Accept plain paths, file:// URLs, and already-mangled "/C:/..." strings
    (persisted by old buggy code before it stripped file:// by hand).

    Uses QUrl.toLocalFile() rather than a manual string strip — stripping
    "file://" by hand leaves a leading slash before a Windows drive letter
    (e.g. "/C:/Users/...", not a valid absolute path), which QUrl's
    platform-aware conversion handles correctly.
    """
    if path_or_url.startswith("file:"):
        return Path(QUrl(path_or_url).toLocalFile())
    # ponytail: repair values saved by the old regex-stripping QML code
    return Path(_MANGLED_DRIVE_RE.sub(r"\1", path_or_url))


def slot_error_boundary(func):
    """Wrap a @Slot method so exceptions are logged + signalled to QML.

    Usage (stack under @Slot):
        @Slot()
        @slot_error_boundary
        def myMethod(self) -> None:
            ...

    On exception:
      - Logs full traceback via logger.exception()
      - Emits logMessage signal with human-readable error (if available)
      - Returns None so QML never sees a crash
    """
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        try:
            return func(self, *args, **kwargs)
        except Exception as e:
            logger = logging.getLogger(self.__class__.__module__)
            logger.exception("Slot '%s' raised: %s", func.__name__, e)
            if hasattr(self, "logMessage"):
                self.logMessage.emit(f"Error in {func.__name__}: {str(e)}")
            return None
    return wrapper
