# ashyterm/helpers.py

from typing import Set
from urllib.parse import urlparse

from gi.repository import Gtk

from .utils.logger import get_logger
from .utils.security import InputSanitizer


def is_valid_url(text: str) -> bool:
    """True for URLs (http, ftp, mailto, …) and bare email addresses."""
    if not text:
        return False

    stripped_text = text.strip()

    # Detect bare emails (no scheme) that urlparse would miss.
    # Reject 'user@host' (no TLD) and anything already scheme-prefixed.
    if "@" in stripped_text and "." in stripped_text.split("@")[-1]:
        if not any(stripped_text.startswith(s) for s in ["http", "ftp", "mailto"]):
            return True

    try:
        result = urlparse(stripped_text)
        return bool(result.scheme and result.netloc)
    except Exception:
        return False


def generate_unique_name(base_name: str, existing_names: Set[str]) -> str:
    """Append ``(n)`` to ``base_name`` until it doesn't collide with the set."""
    logger = get_logger("ashyterm.helpers")
    try:
        sanitized_base = InputSanitizer.sanitize_filename(base_name)
        if sanitized_base not in existing_names:
            return sanitized_base
        counter = 1
        while f"{sanitized_base} ({counter})" in existing_names:
            counter += 1
        return f"{sanitized_base} ({counter})"
    except Exception as e:
        logger.error(f"Error generating unique name for '{base_name}': {e}")
        # Fallback if sanitizer itself throws.
        if base_name not in existing_names:
            return base_name
        counter = 1
        while f"{base_name} ({counter})" in existing_names:
            counter += 1
        return f"{base_name} ({counter})"


def accelerator_to_label(accelerator: str) -> str:
    """Convert GTK accelerator string to a human-readable label."""
    if not accelerator:
        return ""

    def _manual_conversion(accel_str: str) -> str:
        clean_accel = accel_str.replace("<", "").replace(">", "+")
        replacements = {
            "Control": "Ctrl",
            "Shift": "Shift",
            "Alt": "Alt",
            "Super": "Super",
            "Meta": "Meta",
        }
        result = clean_accel
        for old, new in replacements.items():
            result = result.replace(old, new)

        key_replacements = {
            "plus": "+",
            "minus": "-",
            "Return": "Enter",
            "BackSpace": "Backspace",
            "Delete": "Del",
            "Insert": "Ins",
            "space": "Space",
            "Tab": "Tab",
            "Escape": "Esc",
            "comma": ",",
            "period": ".",
            "slash": "/",
            "backslash": "\\",
            "semicolon": ";",
            "apostrophe": "'",
            "grave": "`",
            "bracketleft": "[",
            "bracketright": "]",
            "equal": "=",
        }
        parts = result.split("+")
        if parts:
            last_part = parts[-1].lower()
            for old_key, new_key in key_replacements.items():
                if last_part == old_key:
                    parts[-1] = new_key
                    break
            else:
                if len(parts[-1]) == 1:
                    parts[-1] = parts[-1].upper()
        return "+".join(parts)

    try:
        success, keyval, mods = Gtk.accelerator_parse(accelerator)
        if not success or keyval == 0:
            return _manual_conversion(accelerator)

        key_name = Gtk.accelerator_get_label(keyval, mods)
        return key_name if key_name else _manual_conversion(accelerator)
    except Exception:
        return _manual_conversion(accelerator)


def clear_children(widget: Gtk.Widget) -> None:
    """Remove every direct child from ``widget``.

    Several dialogs and sidebar panels rebuild their content when state
    changes; they all need to empty the container first. Unifying on
    one helper avoids the six copies of
    ``while (child := box.get_first_child()) is not None: box.remove(child)``
    that used to live in the UI layer.
    """
    while (child := widget.get_first_child()) is not None:
        widget.remove(child)


def create_themed_popover_menu(menu_model, parent_widget=None):
    """PopoverMenu with the ashyterm-popover CSS class for consistent theming.

    Prefer this over ``Gtk.PopoverMenu.new_from_model`` directly.
    """
    popover = Gtk.PopoverMenu.new_from_model(menu_model)
    popover.add_css_class("ashyterm-popover")
    popover.set_autohide(True)
    popover.set_has_arrow(False)

    if parent_widget is not None:
        if popover.get_parent() is not None:
            popover.unparent()
        popover.set_parent(parent_widget)

    return popover
