# vim:spell:spelllang=fr
# -*- encoding: utf-8 -*-

import logging
import textwrap

from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.views.generic.edit import FormView
from django.contrib.auth import authenticate, login
from django.shortcuts import redirect
from django.utils.http import urlencode
from django.http import HttpResponseRedirect
from django.contrib import messages
from django.conf import settings
from django.http import Http404
from django.db.models import Q
from fiber.models import Page

import appli_project.appli_socle.views as socle_views
import appli_project.appli_socle.models as models
from appli_project.appli_socle.backends import ProfilRechercheAuthentification
import forms
import appli_project.appli_socle.forms
from appli_project.appli_socle.utils import extraire_action_and_model, \
        extra_sauvegardee, mail_avec_modele

class ProfilRechercheView(socle_views.SeulementPourProfil,
        socle_views.ValidationCharteQualite):
    login_url = '/recherche/connexion/'
    profil = (models.ProfilRecherche,)

    def get_context_data(self, **kwargs):
        ctx = super(ProfilRechercheView, self).get_context_data(**kwargs)
        if socle_views.is_webmaster(self.request.user):
            ctx['loyer_modere'] = True
        else:
            ctx['loyer_modere'] = self.request.user.type_d_offre.filter(nom__contains=u'prix modéré').exists()
        return ctx

def annonces_sauvegardees_actions(request):
    action, annonce = extraire_action_and_model(request,
            ('supprimer', 'enregistrer'), models.Annonce)
    if action == 'supprimer':
        request.user.annonces_sauvegardees.remove(annonce)
        request.record('supprime-annonce-sauvegardee',
                _(u'supprime l\'annonce sauvegardée {annonce}'),
                annonce=annonce)
    elif action == 'enregistrer':
        request.user.annonces_sauvegardees.add(annonce)
        request.record('sauve-annonce',
                _(u'sauve l\'annonce {annonce}'),
                annonce=annonce)

class Accueil(ProfilRechercheView, socle_views.ValidationCGU,
        TemplateView):
    template_name = 'appli_recherche/accueil.html'

    def get_context_data(self, **kwargs):
        context = super(Accueil, self).get_context_data(**kwargs)
        types_logement = set([a for a, b in models.TYPE_LOGEMENT])
        quadrants = set([a for a,b in models.QUADRANTS])
        default = {
                'type_de_logement': list(types_logement),
                'paris_et_alentours': 'paris',
                'quadrants': list(quadrants),
                'montant_loyer': None,
                'duree_location': None}
        if 'reset' not in self.request.GET:
            default['quadrants'] = self.request.GET.getlist('quadrants',
                    default['quadrants'])
            default['type_de_logement'] = self.request.GET.getlist(
                    'type_de_logement', default['type_de_logement'])
            default['paris_et_alentours'] = \
                self.request.GET.get('paris_et_alentours',
                    default['paris_et_alentours'])
            default['montant_loyer'] = self.request.GET.get('montant_loyer')
            default['duree_location'] = self.request.GET.get('duree_location')
        if 'submit' in self.request.GET:
            form = context['form'] = forms.RechercheForm(initial=default,
                    data=self.request.GET, request=self.request)
        else:
            form = context['form'] = forms.RechercheForm(initial=default,
                    request=self.request)
        if socle_views.is_webmaster(self.request.user):
            context['annonces'] = []
            return context 

        qs = models.Annonce.objects.filter(etat_validation='publiee')
        # uniquement les annonces autorisées pour cet utilisateur
        qs = qs.filter(type_d_offre__in=self.request.user.type_d_offre.all()|models.TypeOffre.objects.filter(id=1))
        # filtre les annonces en fonction des critères sélectionnés
        if form.is_valid():
            if default['paris_et_alentours'] == 'paris':
                qs = qs.filter(ville__icontains='Paris')
            if default['quadrants'] and set(default['quadrants']) != quadrants:
                qs = qs.filter(zones__nom__in=default['quadrants'])
            if default['type_de_logement'] and set(default['type_de_logement']) != types_logement:
                qs = qs.filter(type_de_logement__in=default['type_de_logement'])
            if form.cleaned_data.get('montant_loyer') is not None:
                montant_loyer = form.cleaned_data.get('montant_loyer')
                if montant_loyer == 0:
                    qs = qs.filter(prix_par_mois__lte=500)
                elif montant_loyer == 1:
                    qs = qs.filter(prix_par_mois__gte=500, prix_par_mois__lte=700)
                elif montant_loyer == 2:
                    qs = qs.filter(prix_par_mois__gte=700)
            if form.cleaned_data.get('duree_location') is not None:
                duree_location = form.cleaned_data.get('duree_location')
                qs = qs.filter(Q(duree_location=duree_location)|Q(duree_location__isnull=True))
        qs = extra_sauvegardee(qs, self.request.user)
        qs = qs.prefetch_related('prestations', 'prestations__type_de_prestation')
        context['annonces'] = qs
        return context

    def get(self, request, *args, **kwargs):
        if 'sauvegarder' in request.GET:
            return redirect('/recherche/mes-alertes/?%s' % request.GET.urlencode())
        return super(Accueil, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        annonces_sauvegardees_actions(request)
        return super(Accueil, self).get(request, *args, **kwargs)

class Connexion(socle_views.VueRelaieMixin, FormView):
    connexion_ent_class = forms.ConnexionEntForm
    form_class = appli_project.appli_socle.forms.BaseAuthentificationForm
    template_name = 'appli_recherche/connexion.html'
    static_next_url = '/recherche'

    def get_context_data(self, **kwargs):
        d = super(Connexion, self).get_context_data(**kwargs)
        d['connexion_ent_form'] = self.connexion_ent_class()
        return d

    def get_form_kwargs(self):
        kwargs = super(Connexion, self).get_form_kwargs()
        kwargs['profil'] = (models.ProfilRecherche,)
        kwargs['submit_id'] = 'connexion-recherche'
        return kwargs

    def get_success_url(self):
        return self.next_url()

    def return_url(self):
        params = {'next': self.next_url() or '/recherche', 'nopassive': 1}
        local_url = '%s?%s'% (self.request.path, urlencode(params))
        return self.request.build_absolute_uri(local_url)

    def get(self, request, *args, **kwargs):
        if 'ticket' in request.GET:
            service = self.return_url()
            user = authenticate(cas_ticket=request.GET['ticket'],
                    service=service)
            if user and user.is_active:
                login(request, user)
                request.record('connexion', 'connexion via CAS',
                        ticket=request.GET['ticket'])
                response = redirect(self.next_url())
                return response
            elif user and not user.is_active:
                request.record('echec-de-connexion',
                        _(u'tentative de connexion CAS échouée avec '
                          u'l\'identifiant {cas_user}: ce compte '
                          u'est bloqué'),
                        cas_user=user.utilisateur_cas.all()[0].identifiant,
                        user=user, ticket=request.GET['ticket'])
                messages.error(request, _(u"Votre compte est bloqué sur ce "
                    u"service. Veuillez prendre contact avec le service du "
                    u"logement."))
            else:
                messages.error(request, _(u"L'authentification ENT a échoué, "
                    u"essayez encore. Si vous n'êtes pas étudiant, contactez le "
                    u"service logement pour activer votre compte sur cette application."))
        else:
            if 'nopassive' not in request.GET:
                return ProfilRechercheAuthentification.redirect_to_cas(request, service=self.return_url(),
                        passif=True)
        return super(Connexion, self).get(request, *args, **kwargs)

    def form_valid(self, form):
        login(self.request, form.user_cache)
        return super(Connexion, self).form_valid(form)

    def post(self, request, *args, **kwargs):
        if 'compte-ent' in request.POST:
            return ProfilRechercheAuthentification.redirect_to_cas(request,
                    service=self.return_url())
        return super(Connexion, self).post(request, *args, **kwargs)

class MesAlertes(ProfilRechercheView, FormView):
    form_class = forms.AlerteForm
    template_name = 'appli_recherche/mes-alertes.html'
    max_alertes = 10

    def get_form_kwargs(self, **kwargs):
        kwargs = super(MesAlertes, self).get_form_kwargs(**kwargs)
        if self.request.method == 'GET':
            kwargs['initial'] = {
                'paris_et_alentours': 'paris',
                'quadrants': dict(models.QUADRANTS).keys() }
            if self.request.GET:
                kwargs['data'] = self.request.GET
        return kwargs

    def form_valid(self, form):
        if self.request.user.recherches_sauvegardees.count() < self.max_alertes:
            recherche_sauvegardee = models.RechercheSauvegardee.objects.create(
                    types_de_logement=','.join(form.cleaned_data['type_de_logement']),
                    intra_muros=form.cleaned_data['paris_et_alentours']=='paris',
                    duree_location=form.cleaned_data['duree_location'],
                    montant_loyer=form.cleaned_data['montant_loyer'])
            recherche_sauvegardee.zones = models.Zone.objects.filter(nom__in=form.cleaned_data['quadrants'])
            self.request.record('nouvelle-alerte',
                    _(u'sauve une recherche comme alerte email {alerte}'),
                    alerte=recherche_sauvegardee,
                    **form.cleaned_data)
            self.request.user.recherches_sauvegardees.add(recherche_sauvegardee)
        return super(MesAlertes, self).form_valid(form)

    def get_context_data(self, **kwargs):
        ctx = super(MesAlertes, self).get_context_data(**kwargs)
        ctx['max_alertes'] = self.max_alertes
        if socle_views.is_webmaster(self.request.user):
            import random
            ctx['alertes'] = models.RechercheSauvegardee.objects.all()[:random.randint(0,3)]
        else:
            ctx['alertes'] = self.request.user.recherches_sauvegardees.all()
        ctx['QUADRANTS'] = models.QUADRANTS
        return ctx

    def post(self, request, *args, **kwargs):
        action, alerte = extraire_action_and_model(request, ('supprimer',), models.RechercheSauvegardee)
        if action:
            request.record('supprime-alerte', (u'supprime l\'alerte {alerte}'), alerte=alerte)
            alerte.delete()
            return HttpResponseRedirect('')
        return super(MesAlertes, self).post(request, *args, **kwargs)

    def get_success_url(self):
        return ''

class MesAnnonces(ProfilRechercheView, TemplateView):
    '''Page de traitement des annonces'''
    template_name = 'appli_recherche/mes-annonces.html'

    def get_context_data(self, **kwargs):
        ctx = super(MesAnnonces, self).get_context_data(**kwargs)
        if not socle_views.is_webmaster(self.request.user):
            qs = self.request.user.annonces_sauvegardees.filter(etat_validation='publiee')
            qs = qs.extra(select={'sauvegardee': '1'})
            qs = qs.prefetch_related('prestations',
                    'prestations__type_de_prestation')
        else:
            qs = models.Annonce.objects.filter(etat_validation='publiee')[:5]
        ctx['annonces'] = qs
        return ctx

    def post(self, request, *args, **kwargs):
        annonces_sauvegardees_actions(request)
        return super(MesAnnonces, self).get(request, *args, **kwargs)

class ReservedAnnounceMixin(object):
    def get_queryset(self):
        qs = self.model.objects
        if socle_views.is_webmaster(self.request.user):
            return qs.all()
        else:
            # uniquement les annonces autorisées pour cet utilisateur
            return qs.filter(
                 type_d_offre__in=self.request.user.type_d_offre.all()
               | models.TypeOffre.objects.filter(id=1))

class Contact(ReservedAnnounceMixin, ProfilRechercheView, SingleObjectMixin, FormView):
    '''Formulaire de contact des propriétaires'''
    form_class = forms.ContactAnnonceForm
    template_name = 'appli_recherche/contact.html'
    model = models.Annonce
    success_url = '../..'

    def get_context_data(self, **kwargs):
        ctx = FormView.get_context_data(self, **kwargs)
        ctx['annonce'] = self.get_object()
        return ctx

    def post(self, request, *args, **kwargs):
        if 'annuler' in request.POST:
            return HttpResponseRedirect('../../')
        return super(Contact, self).post(request, *args, **kwargs)

    def form_valid(self, form):
        variables = {}
        annonce = variables['annonce'] = self.get_object()
        message = variables['message'] = textwrap.fill(form.cleaned_data['message'], 70)
        variables['base_url'] = self.request.build_absolute_uri('/')
        variables['host'] = self.request.META['HTTP_HOST']
        sujet_par_defaut = '''Demande de contact une annonce publiée sur {{host}}'''
        texte_par_defaut = '''{% load url from future %}Vous recevez ce mail car votre annonce:

        {{ base_url }}{% url 'editer-annonce' pk=annonce.id %}

a attiré l'attention d'un étudiant ou d'un chercheur de l'université Paris
Dauphine. Voici son messages de contact:

==========================================================================
{{ message }}
==========================================================================

Pour lui répondre il vous suffit de répondre à ce mail.'''
        headers = { 'Reply-To': self.request.user.email }
        mail_avec_modele('Contact', sujet_par_defaut, texte_par_defaut,
                variables, settings.CONTACT_FROM, annonce.proprietaire.email,
                headers=headers)
        messages.info(self.request,
                _(u"Un email de contact a été envoyé au propriétaire"
                  u" de l'annonce"))
        self.request.record('contact-annonceur', _(u'contacte l\'annonceur '
                u'{annonceur} à propos de l\'annonce {annonce}'),
                annonceur=annonce.proprietaire, annonce=annonce,
                email=annonce.proprietaire.email, message=message)
        return super(Contact, self).form_valid(form)

class FiberAddendum(object):
    def get_context_data(self, **kwargs):
        ctx = super(FiberAddendum, self).get_context_data(**kwargs)
        ctx['fiber_page'] = Page.objects.get(url__exact='recherche')
        return ctx

class Annonce(ReservedAnnounceMixin, ProfilRechercheView, FiberAddendum, DetailView):
    template_name = 'appli_recherche/annonce-detail.html'
    model = models.Annonce
    context_object_name = "annonce"

    def get(self, request, *args, **kwargs):
        try:
            return super(Annonce, self).get(request, *args, **kwargs)
        except Http404:
            self.object = None
            return self.render_to_response(self.get_context_data(object=None))
