# -*- encoding: utf-8 -*-
from datetime import date

import django.forms
import django.http
from django.contrib import auth
from django.contrib.auth.mixins import LoginRequiredMixin, \
    PermissionRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse
from django.utils.translation import ugettext as _
from django.views import generic

from events.mixins import EventDetailMixin
from kasu import xlsx
from . import forms, models
from .mixins import MahjongMixin

KYU_DAN_ORDER = {  # map sort URL args to Django ORM order_by args
    '+full_name': ('user__last_name', 'user__first_name'),
    '-full_name': ('-user__last_name', '-user__first_name'),
    '+hanchan_count': ('hanchan_count',),
    '-hanchan_count': ('-hanchan_count',),
    '+rank': ('-kyu', 'dan'),
    '-rank': ('-dan', 'kyu'),
    '+score': ('dan_points', '-dan', 'kyu_points'),
    '-score': ('-dan_points', 'dan', '-kyu_points'),
    '+username': ('user__username',),
    '-username': ('-user__username',)
}


class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin,
                    generic.DeleteView):
    """Deletes a Hanchan if confimration has been answerd with 'yes'."""
    form_class = forms.HanchanForm
    model = models.Hanchan
    permission_required = 'mahjong_ranking.delete_hanchan'
    pk_url_kwarg = 'hanchan'

    def get_success_url(self):
        """
        Return to the HachanList of the event form the deleted hanchan.
        :return: URL of the EventHanchanList for the event
        """
        return reverse('event-hanchan-list',
                       kwargs={'event': self.object.event.pk})


class HanchanForm(SuccessMessageMixin, EventDetailMixin,
                  PermissionRequiredMixin, generic.UpdateView):
    """
    A Form to add a new or edit an existing Hanchan.
    """
    form_class = forms.HanchanForm
    model = models.Hanchan
    permission_required = 'mahjong_ranking.add_hanchan'

    def get_form_class(self):
        """
        Users with hanchan edit persmission can also un-/confirm hanchans.
        :return: forms.HanchanForm, or forms.HanchanAdminForm
        """
        return forms.HanchanAdminForm if self.request.user.has_perm(
            'mahjong_ranking.change_hanchan') else forms.HanchanForm

    def get_object(self, queryset=None):
        """
        load the hanchan form the db, or create a new one with the event set.
        Also sets the event attribute.
        :param queryset:
        :return: models.Hanchan object
        """
        if self.kwargs.get('hanchan') and self.request.user.has_perm(
                'mahjong_ranking.change_hanchan'):
            hanchan = self.model.objects.get(id=self.kwargs['hanchan'])
            self.event = hanchan.event
        elif self.kwargs.get('event'):
            self.event = models.Event.objects.get(id=self.kwargs['event'])
            hanchan = models.Hanchan(
                event=self.event,
                start=self.event.start
            )
        return hanchan

    def get_success_url(self):
        """
        Adding a new Hanchan redirect to create_hanchan form.
        Editing an exiting one: redierect to the Hanchanevent.
        """
        if self.kwargs.get('hanchan'):
            return self.object.get_absolute_url()
        else:
            return reverse('add-hanchan-form', kwargs={'event': self.event.pk})

    def get_success_message(self, cleaned_data):
        """
        Get the right sucsess message for the django notification subsystem.
        :param cleaned_data:
        :return: Sucsess message
        """
        if self.kwargs.get('hanchan'):
            return _('%s has been updated successfully.') % self.object
        else:
            return _(
                '%s has been added successfully. You can now add a new '
                'one.') % self.object


class EventHanchanList(EventDetailMixin, generic.ListView):
    "List all hanchans played on a given event."
    model = models.Hanchan
    template_name = 'mahjong_ranking/eventhanchan_list.html'


class EventRankingList(EventDetailMixin, generic.ListView):
    """Display the event ranking for the given event."""
    model = models.EventRanking


class KyuDanRankingList(MahjongMixin, generic.ListView):
    """List all Players with an Kyu or Dan score. """
    default_order = '-score'
    order_by = ''
    paginate_by = 25

    def dispatch(self, request, *args, **kwargs):
        """Set the order_by settings, revert to default_order if necessary."""
        self.order_by = KYU_DAN_ORDER[
            kwargs.get('order_by', self.default_order)
        ]
        return super(KyuDanRankingList, self).dispatch(request, *args, **kwargs)

    def get_queryset(self):
        queryset = models.KyuDanRanking.objects.filter(
            hanchan_count__gt=0).order_by(*self.order_by)
        return queryset.select_related()


class SeasonRankingList(MahjongMixin, generic.ListView):
    model = models.SeasonRanking
    paginate_by = 25
    season = None

    def get_queryset(self):
        self.season = int(self.kwargs.get('season', date.today().year))
        queryset = self.model.objects.filter(
            season=self.season,
            placement__isnull=False
        )
        return queryset.select_related()


class PlayerScore(LoginRequiredMixin, generic.ListView):
    paginate_by = 25
    user = auth.get_user_model()

    def get(self, request, *args, **kwargs):
        user_model = auth.get_user_model()
        try:
            self.user = user_model.objects.get(
                username=self.kwargs.get('username'))
        except user_model.DoesNotExist:
            raise django.http.Http404(
                _("No user found matching the name {}").format(
                    self.kwargs.get('username')))
        print(request.GET)
        if request.GET.get('download') == 'xlsx':
            return self.get_xlsx(request, *args, **kwargs)
        return super(PlayerScore, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = generic.ListView.get_context_data(self, **kwargs)
        context['membership'] = self.user
        try:
            context['kyu_dan_ranking'] = models.KyuDanRanking.objects.get(
                user=self.user)
        except models.KyuDanRanking.DoesNotExist:
            context['ranking'] = None
        try:
            context['ladder_ranking'] = models.SeasonRanking.objects.get(
                user=self.user,
                season=date.today().year)
        except models.SeasonRanking.DoesNotExist:
            context['ladder_ranking'] = models.SeasonRanking(user=self.user)
        return context

    def get_xlsx(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        response = django.http.HttpResponse(
            content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
        response['Content-Disposition'] = 'attachment; ' \
                                          'filename="{xlsx_filename}"'.format(
            xlsx_filename=self.xlsx_filename)
        xlxs_workbook = xlsx.Workbook()
        xlxs_workbook.generate_sheet(
            title=self.xlsx_filename.split('.')[0],
            columns_settings=self.xlsx_columns,
            object_list=self.object_list
        )
        xlxs_workbook.save(response)
        return response


class PlayerDanScore(PlayerScore):
    template_name = 'mahjong_ranking/player_dan_score.html'

    def get_queryset(self):
        self.kyu_dan_ranking = models.KyuDanRanking.objects.get(user=self.user)
        return models.Hanchan.objects.dan_hanchans(
            user=self.user,
            since=self.kyu_dan_ranking.legacy_date)

    @property
    def xlsx_columns(self):
        return (
            {'col': 'A', 'title': 'Beginn', 'attr': 'start',
             'style': 'Date Time',
             'width': 14, 'footer': self.kyu_dan_ranking.legacy_date},
            {'col': 'B', 'title': 'Termin', 'attr': 'event.name',
             'style': 'Content', 'width': 16},
            {'col': 'C', 'title': 'Platzierung', 'attr': 'placement',
             'style': 'Integer', 'width': 11},
            {'col': 'D', 'title': 'Spieler 1', 'attr': 'player1.username',
             'style': 'Content', 'width': 16},
            {'col': 'E', 'title': 'Punkte', 'attr': 'player1_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'F', 'title': 'Spieler 2', 'attr': 'player2.username',
             'style': 'Content', 'width': 16},
            {'col': 'G', 'title': 'Punkte', 'attr': 'player2_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'H', 'title': 'Spieler 3', 'attr': 'player3.username',
             'style': 'Content', 'width': 16},
            {'col': 'I', 'title': 'Punkte', 'attr': 'player3_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'J', 'title': 'Spieler 4', 'attr': 'player4.username',
             'style': 'Content', 'width': 16},
            {'col': 'K', 'title': 'Punkte', 'attr': 'player4_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'L', 'title': 'Dan Punkte', 'attr': 'dan_points',
             'style': 'Integer', 'width': 12,
             'footer': self.kyu_dan_ranking.legacy_dan_points},
            {'col': 'M', 'title': 'Anmerkung', 'attr': 'player_comment',
             'style': 'Content', 'width': 20, 'footer': 'Legacy Dan Punkte'},
        )

    @property
    def xlsx_filename(self):
        return "{username}_dan_score.xlsx".format(username=self.user.username)


class PlayerInvalidScore(PlayerScore):
    template_name = 'mahjong_ranking/player_invalid_score.html'

    def get_queryset(self):
        self.xlsx_filename = "{username}_invalid_score.xlsx".format(
            username=self.user.username)
        return models.Hanchan.objects.unconfirmed(user=self.user)


class PlayerKyuScore(PlayerScore):
    template_name = 'mahjong_ranking/player_kyu_score.html'

    def get_queryset(self):
        self.kyu_dan_ranking = models.KyuDanRanking.objects.get(user=self.user)
        return models.Hanchan.objects.kyu_hanchans(
            user=self.user,
            since=self.kyu_dan_ranking.legacy_date)

    @property
    def xlsx_columns(self):
        return (
            {'col': 'A', 'title': 'Beginn', 'attr': 'start',
             'style': 'Date Time',
             'width': 14, 'footer': self.kyu_dan_ranking.legacy_date},
            {'col': 'B', 'title': 'Termin', 'attr': 'event.name',
             'style': 'Content', 'width': 16},
            {'col': 'C', 'title': 'Platzierung', 'attr': 'placement',
             'style': 'Integer', 'width': 11},
            {'col': 'D', 'title': 'Spieler 1', 'attr': 'player1.username',
             'style': 'Content', 'width': 16},
            {'col': 'E', 'title': 'Punkte', 'attr': 'player1_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'F', 'title': 'Spieler 2', 'attr': 'player2.username',
             'style': 'Content', 'width': 16},
            {'col': 'G', 'title': 'Punkte', 'attr': 'player2_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'H', 'title': 'Spieler 3', 'attr': 'player3.username',
             'style': 'Content', 'width': 16},
            {'col': 'I', 'title': 'Punkte', 'attr': 'player3_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'J', 'title': 'Spieler 4', 'attr': 'player4.username',
             'style': 'Content', 'width': 16},
            {'col': 'K', 'title': 'Punkte', 'attr': 'player4_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'L', 'title': 'Kyū Punkte', 'attr': 'kyu_points',
             'style': 'Integer', 'width': 12,
             'footer': self.kyu_dan_ranking.legacy_kyu_points},
            {'col': 'M', 'title': 'Anmerkung', 'attr': 'comment',
             'style': 'Content', 'width': 24, 'footer': 'Legacy Kyū Punkte'},
        )

    @property
    def xlsx_filename(self):
        return "{username}_kyu_score.xlsx".format(username=self.user.username)


class PlayerLadderScore(PlayerScore):
    season = None
    template_name = 'mahjong_ranking/player_ladder_score.html'

    def get_context_data(self, **kwargs):
        context = super(PlayerLadderScore, self).get_context_data(**kwargs)
        context['season'] = self.season
        context['season_start'] = date(year=self.season, month=1, day=1)
        context['season_end'] = date(year=self.season, month=12, day=31)
        context['season_list'] = models.SeasonRanking.objects.season_list
        return context

    def get_queryset(self, **kwargs):
        self.season = int(self.request.GET.get('season', date.today().year))
        hanchan_list = models.Hanchan.objects.season_hanchans(
            user=self.user,
            season=self.season
        )
        return hanchan_list

    @property
    def xlsx_columns(self):
        return (
            {'col': 'A', 'title': 'Beginn', 'attr': 'start',
             'style': 'Date Time', 'width': 14},
            {'col': 'B', 'title': 'Termin', 'attr': 'event.name',
             'style': 'Content', 'width': 16},
            {'col': 'C', 'title': 'Platzierung', 'attr': 'placement',
             'style': 'Integer', 'width': 11},
            {'col': 'D', 'title': 'Spieler 1', 'attr': 'player1.username',
             'style': 'Content', 'width': 16},
            {'col': 'E', 'title': 'Punkte', 'attr': 'player1_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'F', 'title': 'Spieler 2', 'attr': 'player2.username',
             'style': 'Content', 'width': 16},
            {'col': 'G', 'title': 'Punkte', 'attr': 'player2_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'H', 'title': 'Spieler 3', 'attr': 'player3.username',
             'style': 'Content', 'width': 16},
            {'col': 'I', 'title': 'Punkte', 'attr': 'player3_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'J', 'title': 'Spieler 4', 'attr': 'player4.username',
             'style': 'Content', 'width': 16},
            {'col': 'K', 'title': 'Punkte', 'attr': 'player4_game_score',
             'style': 'Integer', 'width': 8},
            {'col': 'L', 'title': 'Punkte', 'attr': 'game_score',
             'style': 'Integer', 'width': 8},
        )

    @property
    def xlsx_filename(self):
        return "{username}_ladder_score_{season}.xlsx".format(
            username=self.user.username,
            season=self.season
        )
