from django import forms
from django.conf import settings
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.db.models import Count
from django.templatetags.l10n import unlocalize

from .models import (
    Event, EventRole,
    ClassicalWork, ClassicalWorkRole, ClassicalWorkSelection,
    DancePiece, DancePieceRole, DancePieceSelection,
    Movie, MovieRole, MovieSelection,
    Play, PlayRole, PlaySelection,
    Venue
)


# ROLE INLINES.

class RoleInline(admin.TabularInline):
    "Parent class for the other *RoleInlines."
    fields = ( 'creator', 'role_name', 'role_order',)
    raw_id_fields = ('creator',)
    extra = 0

class EventRoleInline(RoleInline):
    model = EventRole

class ClassicalWorkRoleInline(RoleInline):
    model = ClassicalWorkRole

class DancePieceRoleInline(RoleInline):
    model = DancePieceRole

class MovieRoleInline(RoleInline):
    model = MovieRole

class PlayRoleInline(RoleInline):
    model = PlayRole

# WORK SELECTION INLINES.

class ClassicalWorkSelectionInline(admin.TabularInline):
    model = ClassicalWorkSelection
    fields = ('classical_work', 'order',)
    raw_id_fields = ('classical_work',)
    extra = 0

class DancePieceSelectionInline(admin.TabularInline):
    model = DancePieceSelection
    fields = ('dance_piece', 'order',)
    raw_id_fields = ('dance_piece',)
    extra = 0

class MovieSelectionInline(admin.TabularInline):
    model = MovieSelection
    fields = ('movie', 'order',)
    raw_id_fields = ('movie',)
    extra = 0

class PlaySelectionInline(admin.TabularInline):
    model = PlaySelection
    fields = ('play', 'order',)
    raw_id_fields = ('play',)
    extra = 0


# MODEL ADMINS.

@admin.register(Event)
class EventAdmin(admin.ModelAdmin):

    list_display = ('__str__', 'date', 'kind_name', 'venue',)
    list_filter = ('kind', 'date',)
    search_fields = ('title',)

    fieldsets = (
        (None, {
            'fields': ( 'kind', 'date', 'venue', 'title', 'title_sort', 'slug', 'note',)
        }),
        ('Times', {
            'classes': ('collapse',),
            'fields': ('time_created', 'time_modified',)
        }),
    )

    raw_id_fields = ('venue',)
    readonly_fields = ('title_sort', 'slug', 'time_created', 'time_modified',)

    inlines = [ClassicalWorkSelectionInline, DancePieceSelectionInline,
                MovieSelectionInline, PlaySelectionInline,
                EventRoleInline, ]


class ProductionAdmin(admin.ModelAdmin):
    """
    A parent class for MovieAdmin and PlayAdmin.
    """
    list_display = ('title', 'show_creators')
    search_fields = ('title',)

    readonly_fields = ('title_sort', 'time_created', 'time_modified',)

    def show_creators(self, instance):
        names = [ str(r.creator) for r in instance.roles.all() ]
        if len(names) == 0:
            return '-'
        elif len(names) <= 3:
            return ', '.join(names)
        else:
            # Too many to list them all.
            return '{} et al.'.format(names[0])
    show_creators.short_description = 'Creators'


@admin.register(ClassicalWork)
class ClassicalWorkAdmin(ProductionAdmin):
    fieldsets = (
        (None, {
            'fields': ( 'title', 'title_sort', 'slug',)
        }),
        ('Times', {
            'classes': ('collapse',),
            'fields': ('time_created', 'time_modified',)
        }),
    )

    readonly_fields = ('title_sort', 'slug', 'time_created', 'time_modified',)
    inlines = [ ClassicalWorkRoleInline, ]


@admin.register(DancePiece)
class DancePieceAdmin(ProductionAdmin):
    fieldsets = (
        (None, {
            'fields': ( 'title', 'title_sort',  'slug',)
        }),
        ('Times', {
            'classes': ('collapse',),
            'fields': ('time_created', 'time_modified',)
        }),
    )

    readonly_fields = ('title_sort', 'slug', 'time_created', 'time_modified',)
    inlines = [ DancePieceRoleInline, ]


@admin.register(Movie)
class MovieAdmin(ProductionAdmin):
    list_display = ('title', 'tidy_year', 'show_creators',)
    list_filter = ('year',)

    fieldsets = (
        (None, {
            'fields': ( 'title', 'title_sort', 'slug', 'year', 'imdb_id',)
        }),
        ('Times', {
            'classes': ('collapse',),
            'fields': ('time_created', 'time_modified',)
        }),
    )

    readonly_fields = ('title_sort', 'slug', 'time_created', 'time_modified',)
    inlines = [ MovieRoleInline, ]

    def tidy_year(self, obj):
        "Stop the year appearing like '2,018' when USE_THOUSAND_SEPARATOR=True"
        return unlocalize(obj.year)



@admin.register(Play)
class PlayAdmin(ProductionAdmin):
    fieldsets = (
        (None, {
            'fields': ( 'title', 'title_sort', 'slug',)
        }),
        ('Times', {
            'classes': ('collapse',),
            'fields': ('time_created', 'time_modified',)
        }),
    )

    readonly_fields = ('title_sort', 'slug', 'time_created', 'time_modified',)
    inlines = [ PlayRoleInline, ]


class CountryListFilter(admin.SimpleListFilter):
    """
    For filtering Venues by country.

    Used so that we only list countries that have at least one Venue assigned
    to them.

    Otherwise we have a very long list of countries, most of which are unused.
    """
    title = 'Country'

    parameter_name = 'country'

    def lookups(self, request, model_admin):
        """
        Returns a list of tuples like:

            [
                ('AU', 'Australia'),
                ('GB', 'UK'),
                ('US', 'USA'),
            ]

        One for each country that has at least one Venue.
        Sorted by the label names.
        """
        list_of_countries = []

        # We don't need the country_count but we need to annotate them in order
        # to group the results.
        qs = Venue.objects.exclude(country='') \
                            .values('country') \
                            .annotate(country_count=Count('country')) \
                            .order_by('country')
        for obj in qs:
            country = obj['country']
            list_of_countries.append(
                (country, Venue.COUNTRIES[country])
            )

        return sorted(list_of_countries, key=lambda c: c[1])

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        if self.value():
            return queryset.filter(country=self.value())
        else:
            return queryset


@admin.register(Venue)
class VenueAdmin(admin.ModelAdmin):
    list_display = ('name', 'address', 'country',)
    list_filter = (CountryListFilter,)
    search_fields = ('name',)

    fieldsets = (
        (None, {
            'fields': ( 'name', 'name_sort', 'latitude', 'longitude',
                        'address', 'country',)
        }),
        ('Times', {
            'classes': ('collapse',),
            'fields': ('time_created', 'time_modified',)
        }),
    )

    readonly_fields = ('name_sort', 'time_created', 'time_modified',)

    class Media:
        if hasattr(settings, 'SPECTATOR_GOOGLE_MAPS_API_KEY') and settings.SPECTATOR_GOOGLE_MAPS_API_KEY:
            css = {
                'all': ('css/admin/location_picker.css',),
            }
            js = (
                'https://maps.googleapis.com/maps/api/js?key={}'.format(settings.SPECTATOR_GOOGLE_MAPS_API_KEY),
                'js/admin/location_picker.js',
            )
