from django.contrib import admin
from django.db import models
from django.forms import ModelForm, BaseInlineFormSet
from django.utils import timezone
from django.core.urlresolvers import reverse
from django.utils.html import format_html
from django.core.mail import mail_managers

from adhesions.models import Adhesion
from djadhere.utils import get_active_filter
from .models import Service, ServiceType, IPResource, Route, ResourceAllocation
from .utils import notify_allocation


### Filters

class ResourceInUseFilter(admin.SimpleListFilter):
    title = 'disponibilité'
    parameter_name = 'available'

    def lookups(self, request, model_admin):
        return (
            (1, 'Disponible'),
            (0, 'Non disponible'),
        )

    def queryset(self, request, queryset):
        now = timezone.now()
        active_filter = get_active_filter('allocation')
        if self.value() == '0': # non disponible
            return queryset.filter(active_filter | models.Q(reserved=True))
        if self.value() == '1': # disponible
            return queryset.exclude(reserved=True).exclude(active_filter)


class AllocationStatusFilter(admin.SimpleListFilter):
    title = 'statut'
    parameter_name = 'status'

    def lookups(self, request, model_admin):
        return (
            (1, 'En cours'),
            (0, 'Terminée'),
        )

    def queryset(self, request, queryset):
        now = timezone.now()
        active_filter = get_active_filter()
        if self.value() == '0': # inactif
            return queryset.exclude(active_filter)
        if self.value() == '1': # actif
            return queryset.filter(active_filter)


### Inlines

class ResourceAllocationInlineFormSet(BaseInlineFormSet):
    def save_new(self, form, commit=True):
        obj = super().save_new(form, commit)
        notify_allocation(self.request, obj)
        return obj

    def save_existing(self, form, instance, commit=True):
        old = ResourceAllocation.objects.get(pk=instance.pk)
        notify_allocation(self.request, instance, old)
        return super().save_existing(form, instance, commit)


class AllocationInline(admin.TabularInline):
    model = ResourceAllocation
    formset = ResourceAllocationInlineFormSet
    extra = 0
    fields = ('id', 'service', 'resource', 'route', 'start', 'end')
    raw_id_fields = ('service', 'resource',)
    verbose_name_plural = 'Allocations'
    show_change_link = True

    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        formset.request = request
        return formset

    def get_max_num(self, request, obj=None, **kwargs):
        existing = obj.allocations.count() if obj else 0
        # pour simplifier la validation, on ajoute qu’une allocation à la fois
        # il faudrait surcharger la méthode clean du formset pour supprimer cette limite
        return existing + 1

    def has_delete_permission(self, request, obj=None):
        return False


### Actions

def ends_resource(resource, request, queryset):
    now = timezone.now()
    queryset.exclude(start__lte=now, end__isnull=False).update(end=now)
    # TODO: send mail
ends_resource.short_description = 'Terminer les allocations sélectionnées'


### ModelAdmin

class ServiceAdmin(admin.ModelAdmin):
    list_display = ('id', 'adhesion', 'get_adherent_link', 'service_type', 'label', 'active')
    list_display_links = ('adhesion',)
    list_select_related = ('adhesion',) # to reduce database requests
    list_filter = (
        'active',
        ('service_type', admin.RelatedOnlyFieldListFilter),
    )
    inlines = (AllocationInline,)
    search_fields = ('id', 'service_type__name', 'label', 'adhesion__id',)
    raw_id_fields = ('adhesion',)

    get_adherent_link = lambda self, service: service.adhesion.get_adherent_link()
    get_adherent_link.short_description = Adhesion.get_adherent_link.short_description

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def has_delete_permission(self, request, obj=None):
        return False


class IPResourceAdmin(admin.ModelAdmin):
    list_display = ('__str__', 'available_display')
    list_filter = (
        ResourceInUseFilter,
        ('prefixes', admin.RelatedOnlyFieldListFilter),
    )
    fields = ('ip', 'reserved', 'notes')
    readonly_fields = ('ip', 'reserved',)
    search_fields = ('ip',)
    inlines = (AllocationInline,)

    def available_display(self, obj):
        return not obj.reserved and not obj.in_use
    available_display.short_description = 'Disponible'
    available_display.boolean = True

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


class RouteAdmin(admin.ModelAdmin):
    fields = ('name',)
    readonly_fields = ('name',)

    def has_add_permission(self, request, obj=None):
        return False

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def has_delete_permission(self, request, obj=None):
        return False


class ResourceAllocationAdmin(admin.ModelAdmin):
    list_display = ('id', 'resource', 'service', 'start', 'end',)
    list_display_links = ('resource', 'service',)
    list_filter = (AllocationStatusFilter,)
    #actions = (ends_resource,)
    raw_id_fields = ('resource', 'service',)
    search_fields = ('resource__ip', 'service__id', 'service__service_type__name', 'service__label')

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def has_delete_permission(self, request, obj=None):
        return False

    def save_model(self, request, obj, form, change):
        if change:
            old_alloc = ResourceAllocation.objects.get(pk=obj.pk)
        else:
            old_alloc = None
        super().save_model(request, obj, form, change)
        notify_allocation(request, obj, old_alloc)


class ServiceTypeAdmin(admin.ModelAdmin):
    fields = ('name',)
    readonly_fields = ('name',)

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


admin.site.register(ServiceType, ServiceTypeAdmin)
admin.site.register(Service, ServiceAdmin)
admin.site.register(IPResource, IPResourceAdmin)
admin.site.register(Route, RouteAdmin)
admin.site.register(ResourceAllocation, ResourceAllocationAdmin)