from django.shortcuts import render
from django.contrib.auth.decorators import permission_required, login_required
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import ensure_csrf_cookie
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
from django.core.mail import send_mail
from django.conf import settings
from django.utils.translation import ugettext as _
from django.forms.models import model_to_dict
from django_tables2.config import RequestConfig

import json
import requests
import logging
import csv

# REST framework
from members.serializers import MemberSerializer
from members.throttles import BurstRateThrottle, SustainedRateThrottle

from rest_framework import generics
from rest_framework import permissions

from members.models import Member, Request, Payment
from members.forms import MemberForm, PaymentForm, ApplicationForm, CSVValidationError, UploadFileForm
from members.tables import MemberTable, PaymentTable, RequestTable
from members.resources import MemberResource, PaymentResource, ApplicationResource


# Can be used to retrieve single member information via REST API
class MemberDetail(generics.RetrieveAPIView):
    """Member detail rest API view."""

    queryset = Member.objects.all()
    serializer_class = MemberSerializer
    permission_classes = (permissions.DjangoModelPermissions, )
    throttle_classes = (BurstRateThrottle, SustainedRateThrottle, )


def error_view(request, message, status=400):
    return render(request, 'error.html', {'error': message}, status=400)


def validate_recaptcha(response):
    """
    Recaptcha is used in member applications.

    :param response:
    :return: Boolean, success or not
    """
    values = {
        'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
        'response': response,
    }
    url = "https://www.google.com/recaptcha/api/siteverify"
    headers = {'Content-type': 'application/x-www-form-urlencoded'}
    resp = requests.post(url, values, headers=headers)
    try:
        result = json.loads(resp.text)
        logging.info('Recaptcha response: {}'.format(result))
        return result["success"]
    except:
        return False


def convert_table_to_html(table, request):
    """
    Convert table to html.

    This is a horrible hack for converting a table object to raw html.
    Even with extensive research I wasn't able to find a way to add a path
    prefix "e.g. /members/list" to the query strings "e.g. ?sort=foo", so I
    did it manually with string.replace.

    Note: When adding the html to a page, you need to run it through
    the "safe" filter. E.g. "{{ table|safe }}"

    :param table: Table object from members.tables
    :param request:  HttpRequest
    :return: Raw html string
    """
    table_as_html = table.as_html(request)
    path = request.path

    fixed = table_as_html.replace(r'href="?', r'href="{}?'.format(path))
    return fixed


@ensure_csrf_cookie
@require_http_methods(["GET"])
@login_required(login_url='/admin/login')
@permission_required('members.change_member', raise_exception=True)
def settings_page(request, *args, **kwargs):
    """Render member app settings page."""
    return render(request, 'settings.html', {})


@ensure_csrf_cookie
@require_http_methods(["POST"])
@login_required(login_url='/admin/login')
@permission_required(['members.change_member', 'members.change_payment'], raise_exception=True)
def import_csv(request, *args, **kwargs):
    """Get csv data imported to page and create members based on that."""
    try:
        csv_in_memory_file = request.FILES.get('csvFile')
        csv_file = csv_in_memory_file.file
        data = csv_file.read().decode('utf-8')

        delimiter = request.POST.get('delimiter', ',')
        payment_source = request.POST['payment_source']
    except:
        return error_view(request, _('Missing CSV file'))

    try:
        result = MemberForm.csv_to_models(data, payment_source=payment_source, delimiter=delimiter)
    except CSVValidationError as ex:
        logging.exception('Model validation error')
        return error_view(request, ex.form_errors)
    except Exception as ex:
        logging.exception('Other error in CSV import')
        return error_view(request, str(ex))

    member_table = MemberTable(result.members,
                               request=request,
                               exclude=['id', 'options'],
                               attrs={'class': 'table table-bordered table-hover'})

    member_table.paginate(page=request.GET.get('page', 1), per_page=999999)
    member_table_html = convert_table_to_html(member_table, request)

    payment_table = PaymentTable(result.payments,
                                 request=request,
                                 exclude=['id', 'options'],
                                 attrs={'class': 'table table-bordered table-hover'})

    payment_table.paginate(page=request.GET.get('page', 1), per_page=999999)
    payment_table_html = convert_table_to_html(payment_table, request)

    request.session['models'] = result
    request.session['payment_source'] = payment_source
    context = {
        'members': member_table_html,
        'payments': payment_table_html
    }
    return render(request, 'member_add_many_confirm.html', context)


def send_mail_wrapper(subject, message, email_to):
    """Send mail to default email."""
    send_mail(subject,
              message,
              settings.DEFAULT_EMAIL_FROM,
              [email_to],
              fail_silently=False)


def make_excel_response(Resource):
    res = Resource()
    dataset = res.export()
    response = HttpResponse(dataset.xlsx, content_type='application/vnd.ms-excel; charset=utf-8')
    response['Content-Disposition'] = 'attachment; filename="export.xlsx"'
    return response


@require_http_methods(['GET'])
def export_members_excel(request, *args, **kwargs):
    return make_excel_response(MemberResource)


@require_http_methods(['GET'])
def export_payments_excel(request, *args, **kwargs):
    return make_excel_response(PaymentResource)


@require_http_methods(['GET'])
def export_applications_excel(request, *args, **kwargs):
    return make_excel_response(ApplicationResource)
