import logging

from django.contrib import admin
from django.db.models import F
from django.template.defaultfilters import truncatechars
from django.utils.safestring import mark_safe

from .models import PackageVersion

logger = logging.getLogger(__name__)


def html_list(data):
    """Convert dict into formatted HTML."""
    if data is None:
        return None
    as_li = lambda v: "<li>%s</li>" % v
    items = [as_li(v) for v in data]
    return mark_safe("<ul>%s</ul>" % ''.join(items))


def check_pypi(modeladmin, request, queryset):
    """Update latest package info from PyPI."""
    for p in queryset:
        if p.is_editable:
            logger.debug("Ignoring version update '%s' is editable", p.package_name)
        else:
            p.update_from_pypi()


check_pypi.short_description = "Update selected packages from PyPI"


class UpdateAvailableListFilter(admin.SimpleListFilter):

    """Enable filtering by packages with an update available."""

    title = "Update available"
    parameter_name = 'update'

    def lookups(self, request, model_admin):
        return (
            ('1', 'Yes'),
            ('0', 'No'),
            ('-1', 'Unknown'),
        )

    def queryset(self, request, queryset):
        """Filter based on whether an update (of any sort) is available."""
        if self.value() == '-1':
            return queryset.filter(latest_version__isnull=True)
        elif self.value() == '0':
            return (
                queryset
                .filter(
                    current_version__isnull=False,
                    latest_version__isnull=False,
                    latest_version=F('current_version')
                )
            )
        elif self.value() == '1':
            return (
                queryset
                .filter(
                    current_version__isnull=False,
                    latest_version__isnull=False
                ).exclude(
                    latest_version=F('current_version')
                )
            )
        else:
            return queryset


class PackageVersionAdmin(admin.ModelAdmin):

    actions = (check_pypi,)
    change_list_template = 'change_list.html'
    list_display = (
        'package_name',
        '_updateable',
        'current_version',
        'next_version',
        'latest_version',
        'supports_py3',
        '_licence',
        'diff_status',
        'checked_pypi_at',
    )
    list_filter = (
        'diff_status',
        'is_editable',
        'is_parseable',
        UpdateAvailableListFilter,
        'supports_py3'
    )
    ordering = ["package_name"]
    readonly_fields = (
        'package_name',
        'is_editable',
        'is_parseable',
        'current_version',
        'next_version',
        'latest_version',
        'diff_status',
        'checked_pypi_at',
        'url',
        'licence',
        'raw',
        'available_updates',
        'python_support',
        'supports_py3',
        'django_support'
    )

    def _licence(self, obj):
        """Return truncated version of licence."""
        return truncatechars(obj.licence, 20)
    _licence.short_description = "PyPI licence"

    def _updateable(self, obj):
        """Return True if there are available updates."""
        if obj.latest_version is None or obj.is_editable:
            return None
        else:
            return obj.latest_version != obj.current_version
    _updateable.boolean = True
    _updateable.short_description = "Update available"

    def available_updates(self, obj):
        """Print out all versions ahead of the current one."""
        from package_monitor import pypi
        package = pypi.Package(obj.package_name)
        versions = package.all_versions()
        return html_list([v for v in versions if v > obj.current_version])


admin.site.register(PackageVersion, PackageVersionAdmin)