import csv
import time
from datetime import timedelta

from django.shortcuts import render, redirect
from django.http import Http404, HttpResponse, HttpResponseForbidden, JsonResponse
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.contrib import messages
from django.utils.html import format_html
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.db import transaction, IntegrityError
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User
from django.contrib.auth.forms import PasswordChangeForm
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.timezone import now

from formtools.wizard.views import SessionWizardView

from .models import Petition, Signature, Organization, PytitionUser, PetitionTemplate, Permission
from .models import SlugModel
from .forms import SignatureForm, ContentFormPetition, EmailForm, NewsletterForm, SocialNetworkForm, ContentFormTemplate
from .forms import StyleForm, PetitionCreationStep1, PetitionCreationStep2, PetitionCreationStep3, UpdateInfoForm
from .forms import DeleteAccountForm, OrgCreationForm
from .helpers import get_client_ip, get_session_user, petition_from_id
from .helpers import check_petition_is_accessible
from .helpers import send_confirmation_email, subscribe_to_newsletter
from .helpers import get_update_form, petition_detail_meta


#------------------------------------
 Views -----------------------------------

# Path : /
# Depending on 
the settings.INDEX_PAGE, show a list of petitions or
# redirect to an user/org profile page
def index(request):
    petitions = Petition.objects.filter(published=True).order_by('-id')[:12]
    if not hasattr(settings, 'INDEX_PAGE'):
        raise Http404(_("You must set an INDEX_PAGE config in your settings"))
    if settings.INDEX_PAGE == 'USER_PROFILE':
        try:
            user_name = settings.INDEX_PAGE_USER
        except:
            raise Http404(_("You must set an INDEX_PAGE_USER config in your settings"))
    elif settings.INDEX_PAGE == 'ORGA_PROFILE':
        try:
            org_name = settings.INDEX_PAGE_ORGA
        except:
            raise Http404(_("You must set an INDEX_PAGE_ORGA config in your settings"))

    if settings.INDEX_PAGE == 'ALL_PETITIONS':
        return redirect("all_petitions")
    elif settings.INDEX_PAGE == 'ORGA_PROFILE':
        org = Organization.objects.get(name=org_name)
        return redirect("org_profile", org.slugname)
    elif settings.INDEX_PAGE == 'USER_PROFILE':
        return redirect("user_profile", user_name)
    elif settings.INDEX_PAGE == 'LOGIN_REGISTER':
        if request.user.is_authenticated:
            return redirect("user_dashboard")
        else:
            return redirect("login")
    else:
        authenticated = request.user.is_authenticated
        if authenticated:
            user = get_session_user(request)
        else:
            user = request.user
        return render(request, 'petition/index.html',
                {
                    'user': user,
                    'petitions': petitions
                }
        )


# /all_petitions
# Show all the petitions in the database
def all_petitions(request):
    petitions = Petition.objects.filter(published=True).all()
    return render(request, 'petition/all_petitions.html',
            {'petitions': petitions})


# /search?q=QUERY
# Show results of a search query
def search(request):
    q = request.GET.get('q', '')
    if q != "":
        petitions = Petition.objects.filter(Q(title__icontains=q) | Q(text__icontains=q)).filter(published=True)[:15]
        orgs = Organization.objects.filter(name__icontains=q)
    else:
        petitions = Petition.objects.filter(published=True)[:15]
        orgs = []
    return render(
        request, 'petition/search.html',
        {
            'petitions': petitions,
            'orgs': orgs,
            'q': q
        }
    )


# /<int:petition_id>/
# Show information on a petition
def detail(request, petition_id):
    petition = petition_from_id(petition_id)
    check_petition_is_accessible(request, petition)
    try:
        pytitionuser = get_session_user(request)
    except:
        pytitionuser = None

    sign_form = SignatureForm(petition=petition)
    ctx = {"user": pytitionuser, 'petition': petition, 'form': sign_form,
           'meta': petition_detail_meta(request, petition_id)}
    return render(request, 'petition/petition_detail.html', ctx)


# /<int:petition_id>/confirm/<confirmation_hash>
# Confirm signature to a petition
def confirm(request, petition_id, confirmation_hash):
    petition = petition_from_id(petition_id)
    check_petition_is_accessible(request, petition)
    try:
        successmsg = petition.confirm_signature(confirmation_hash)
        if successmsg is None:
            messages.error(request, _("Error: This confirmation code is invalid. Maybe you\'ve already confirmed?"))
        else:
            messages.success(request, successmsg)
    except ValidationError as e:
        messages.error(request, _(e.message))
    except Signature.DoesNotExist:
        messages.error(request, _("Error: This confirmation code is invalid."))
    return redirect(petition.url)


# <int:petition_id>/get_csv_signature
# <int:petition_id>/get_csv_confirmed_signature
# returns the CSV files of the list of signatures
@login_required
def get_csv_signature(request, petition_id, only_confirmed):
    user = get_session_user(request)
    try:
        petition = Petition.objects.get(pk=petition_id)
    except Petition.DoesNotExist:
        return JsonResponse({}, status=404)

    if petition.owner_type == "org":
        if not petition.org.is_allowed_to(user, "can_view_signatures"):
            return JsonResponse({}, status=403)

    filename = '{}.csv'.format(petition)
    signatures = Signature.objects.filter(petition = petition)
    if only_confirmed:
        signatures = signatures.filter(confirmed = True)
    else:
        signatures = signatures.all()
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment;filename={}'.format(filename).replace('\r\n', '').replace(' ', '%20')
    writer = csv.writer(response)
    attrs = ['first_name', 'last_name', 'phone', 'email', 'subscribed_to_mailinglist', 'confirmed']
    writer.writerow(attrs)
    for signature in signatures:
        values = [getattr(signature, field) for field in attrs]
        writer.writerow(values)
    return response


# resend/<int:signature_id>
# resend the signature confirmation email
@login_required
def go_send_confirmation_email(request, signature_id):
    app_label = Signature._meta.app_label
    signature = Signature.objects.filter(pk=signature_id).get()
    send_confirmation_email(request, signature)
    return redirect('admin:{}_signature_change'.format(app_label), signature_id)


# <int:petition_id>/sign
# Sign a petition
def create_signature(request, petition_id):
    petition = petition_from_id(petition_id)
    check_petition_is_accessible(request, petition)

    if request.method == "POST":
        form = SignatureForm(petition=petition, data=request.POST)
        if not form.is_valid():
            return render(request, 'petition/petition_detail.html', {'petition': petition, 'form': form, 'meta': petition_detail_meta(request, petition_id)})

        ipaddr = make_password(
                get_client_ip(request),
                salt=petition.salt.encode('utf-8'))
        since = now() - timedelta(seconds=settings.SIGNATURE_THROTTLE_TIMING)
        signatures = Signature.objects.filter(
            petition=petition,
            ipaddress=ipaddr,
            date__gt=since)
        if signatures.count() > settings.SIGNATURE_THROTTLE:
            messages.error(request, _("Too many signatures from your IP address, please try again later."))
            return render(request, 'petition/petition_detail.html', {'petition': petition, 'form': form, 'meta': petition_detail_meta(request, petition_id)})
        else:
     