#!/usr/bin/env python
# -*- coding: utf-8 -*-
from datetime import timedelta

from django.db.models.functions import Lower

from django.views import View
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.detail import SingleObjectMixin

from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone

from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy, reverse

from lostplaces.models import (
    Place,
    PlaceImage,
    PlaceVoting,
    PLACE_LEVELS
)

from lostplaces.views.base_views import (
    IsAuthenticatedMixin,
    IsPlaceSubmitterMixin,
    LevelCapPlaceListView,
    IsEligibleToSeePlaceMixin
)
from lostplaces.views.place_image_views import MultiplePlaceImageUploadMixin
from lostplaces.forms import PlaceForm, PlaceImageForm, TagSubmitForm
from lostplaces.common import redirect_referer_or

from taggit.models import Tag

class PlaceListView(IsAuthenticatedMixin, LevelCapPlaceListView):
    paginate_by = 5
    template_name = 'place/place_list.html'
    ordering = [Lower('name')]

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['mapping_config'] = {
            'all_points': context['place_list'],
            'map_center': Place.average_latlon(context['place_list'])
        }
        return context

class PlaceDetailView(IsAuthenticatedMixin, IsEligibleToSeePlaceMixin, View):
    not_eligible_to_see_message = _('You\'r not allowed to see this place')

    def get_place(self):
        return get_object_or_404(Place, pk=self.kwargs['pk'])

    def get(self, request, pk): 
        place = self.get_place()
        place.calculate_place_level()
        explorer = request.user.explorer

        context = {
            'place': place,
            'mapping_config': {
                'all_points': [ place ],
                'map_center': {'latitude': place.latitude, 'longitude': place.longitude},                                
            },
            'tagging_config': {
                'all_tags': Tag.objects.all(),
                'submit_form': TagSubmitForm(),
                'tagged_item': place,
                'submit_url': reverse('place_tag_submit', kwargs={'tagged_id': place.id}),
                'delete_url_name': 'place_tag_delete'
            },
            'placevoting': {
                'users_vote': PlaceVoting.objects.filter(place=place, submitted_by=explorer).first(),
                'all_choices': reversed(PLACE_LEVELS)
            }
        }
        return render(request, 'place/place_detail.html', context)

class PlaceUpdateView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, SuccessMessageMixin, UpdateView):
    template_name = 'place/place_update.html'
    model = Place
    form_class = PlaceForm
    success_message = _('Successfully updated place')
    place_submitter_error_message = _('You are not allowed to edit this place')

    def get_success_url(self):
        return reverse_lazy('place_detail', kwargs={'pk':self.get_object().pk})

    def get_place(self):
        return self.get_object()

class PlaceCreateView(MultiplePlaceImageUploadMixin, IsAuthenticatedMixin, View):

    def get(self, request, *args, **kwargs):
        place_image_form = PlaceImageForm()
        place_form = PlaceForm()

        context = {
            'place_form': place_form,
            'place_image_form': place_image_form
        }
        return render(request, 'place/place_create.html', context)

    def post(self, request, *args, **kwargs):
        place_form = PlaceForm(request.POST)

        if place_form.is_valid():
            submitter = request.user.explorer
            place = place_form.save(commit=False)
            # Save logged in user as "submitted_by"
            place.submitted_by = submitter
            place.save()

            self.handle_place_images(request, place)
            
            messages.success(
                self.request,
                _('Successfully created place')
            )
            return redirect(reverse_lazy('place_detail', kwargs={'pk': place.pk}))
        
        else:
            # Usually the browser should have checked the form before sending.
            messages.error(
                self.request,
                _('Please fill in all required fields.')
            )
            return render(
                request=request,
                template_name='place/place_create.html',
                context={
                    'place_form': place_form,
                    'place_image_form': PlaceImageForm()
                },
                status=400
            )

class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView):
    template_name = 'place/place_delete.html'
    model = Place
    success_message = _('Successfully deleted place')
    success_url = reverse_lazy('place_list')
    place_submitter_error_message = _('You are not allowed to delete this place')

    def delete(self, request, *args, **kwargs):
        messages.success(self.request, self.success_message)
        return super().delete(request, *args, **kwargs)

    def get_place(self):
        return self.get_object()

class PlaceFavoriteView(IsAuthenticatedMixin, IsEligibleToSeePlaceMixin, View):
    not_eligible_to_see_message = _('You\'r not allowed to favorite this place')

    def get_place(self):
        return get_object_or_404(Place, pk=self.kwargs['place_id'])

    def get(self, request, place_id):
        place = self.get_place()
        if request.user is not None:
            request.user.explorer.favorite_places.add(place)
            request.user.explorer.save()
    
        return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
            
class PlaceUnfavoriteView(IsAuthenticatedMixin, View):

    def get(self, request, place_id):
        place = get_object_or_404(Place, id=place_id)
        if request.user is not None:
            request.user.explorer.favorite_places.remove(place)
            request.user.explorer.save()

        return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))                    

class PlaceVisitCreateView(IsAuthenticatedMixin, IsEligibleToSeePlaceMixin, View):
    not_eligible_to_see_message = _('You\'r not allowed to visit this place :P (Now please stop trying out URL\'s)')

    def get_place(self):
        return get_object_or_404(Place, pk=self.kwargs['place_id'])

    def get(self, request, place_id):
        place = self.get_place()
        if request.user is not None:
            request.user.explorer.visited_places.add(place)
            request.user.explorer.save()
    
        return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
            
class PlaceVisitDeleteView(IsAuthenticatedMixin, View):
    
    def get(self, request, place_id):
        place = get_object_or_404(Place, id=place_id)
        if request.user is not None:
            request.user.explorer.visited_places.remove(place)
            request.user.explorer.save()

        return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))                    


class PlaceVoteView(IsEligibleToSeePlaceMixin, View):
    delta = timedelta(weeks=24)
    
    def get(self, request, place_id, vote):
        place = get_object_or_404(Place, id=place_id)
        explorer = request.user.explorer
        
        voting = PlaceVoting.objects.filter(
            submitted_by=explorer,
            place=place
        ).first()
        
        if voting is None:
            voting = PlaceVoting.objects.create(
                submitted_by=explorer,
                place=place,
                vote=vote,
                expires_when=timezone.now()+self.delta
            )
            messages.success(self.request, _('Vote submitted'))
        else:
            voting.expires_when=timezone.now()+self.delta
            voting.vote = vote
            messages.success(self.request, _('Your vote has been update'))

        voting.save()
        return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))