"""Display models and utility functions"""
import collections
from datetime import datetime
from typing import Any, TYPE_CHECKING

try:
    import notify2
except ImportError:
    notify2 = None
try:
    import notifypy
except ImportError:
    notifypy = None

from . import resources
from .models import prefs

if TYPE_CHECKING:
    from .app import ApplicationContext

NOTIFICATIONS_AVAILABLE = bool(notify2 or notifypy)


def shorten_paths(source_paths) -> dict[Any, Any]:
    """Shorten a sequence of paths into unique strings for display"""
    result = {}
    # Start by assuming that all paths are in conflict.
    # On each iteration we will collect all the path suffixes, move the newly
    # unique entries to the result, and repeat until no conflicts remain.
    count = 0
    conflicts = list(source_paths)
    in_conflict = True
    while in_conflict:
        count += 1
        # Gather the suffixes for the current paths in conflict
        suffixes = collections.defaultdict(list)
        for path in conflicts:
            suffix = path_suffix(path, count)
            suffixes[suffix].append(path)

        # Loop over the suffixes to gather new conflicts and unique entries.
        conflicts = []
        in_conflict = False

        for suffix, paths in suffixes.items():
            # If only a single path exists for the suffix then no conflict
            # exists, and the suffix is valid.
            if len(paths) == 1:
                result[paths[0]] = suffix
            # If this loop runs too long then bail out by using the full path.
            elif count >= 128:
                for path in paths:
                    result[path] = path
            # If multiple paths map to the same suffix then the paths are
            # considered in conflict, and will be reprocessed.
            else:
                conflicts.extend(paths)
                in_conflict = True

    return result


def path_suffix(path: str, count: int) -> str:
    """Return `count` number of trailing path components"""
    path = normalize_path(path)
    components = path.split('/')[-count:]
    return '/'.join(components)


def normalize_path(path: str) -> str:
    """Normalize a path so that only "/" is used as a separator"""
    return path.replace('\\', '/')


def notify(context: 'ApplicationContext', title: str, message: str, icon) -> None:
    """Send a notification using notify2 xor notifypy"""
    app_name = context.app_name
    if notify2:
        notify2.init(app_name)
        notification = notify2.Notification(title, message, icon)
        notification.show()
    elif notifypy:
        notification = notifypy.Notify()
        notification.application_name = app_name
        notification.title = title
        notification.message = message
        notification.icon = icon
        notification.send()
    else:
        context.notifier.log.emit(f'{title}: {message}')


def push_notification(
    context: 'ApplicationContext',
    title: str,
    message: str,
    error: bool = False,
    allow_popups: bool = True,
) -> None:
    """Emit a push notification"""
    if prefs.enable_popups(context) and allow_popups:
        if error:
            context.notifier.critical.emit(title, dict(message=message))
        else:
            context.notifier.information.emit(title, dict(message=message))
    else:
        if error:
            icon = resources.icon_path('git-cola-error.svg')
        else:
            icon = resources.icon_path('git-cola-ok.svg')
        notify(context, title, message, icon)


def git_commit_date(datetime: datetime) -> str:
    """Return the datetime as a string for use by Git"""
    return datetime.strftime('%a %b %d %H:%M:%S %Y %z')
