import urllib

from django.views.generic import View, TemplateView
from django.shortcuts import redirect
from django.core.urlresolvers import reverse_lazy
from django.contrib import messages
from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import HttpResponse
from django.conf import settings
from django.utils import timezone

# stripe related:
from codesy.base.models import User
from .models import StripeEvent
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
import json

import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY


def stripe_debug_values():
    if settings.DEBUG:
        return {
            'identity': {
                'day': '04',
                'month': '07',
                'year': '1976',
                'first_name': 'Joe',
                'last_name': 'Example',
                'street': '36 East Cameron',
                'city': 'Tulsa',
                'zip': '74103',
                'state': 'OK',
                'ssn_last_4': '0000',
                'ssn_full': '000000000',
                'business_name': 'Howdy Dammit LLC',
                'business_tax_id': '000000000'
            },
            'card': {
                'cc_number': '4111111111111111',
                'cc_ex_month': '01',
                'cc_ex_year': '2020',
                'cvc': '123',
            },
            'bank': {
                'name': 'Joe Sample',
                'routing_number': '110000000',
                'account_number': '000123456789',
            }
        }


# stripe related mixins
class CSRFExemptMixin(object):
    @method_decorator(csrf_exempt)
    def dispatch(self, *args, **kwargs):
        return super(CSRFExemptMixin, self).dispatch(*args, **kwargs)


class UserIdentityVerifiedMixin(UserPassesTestMixin):
    login_url = reverse_lazy('identity')
    redirect_field_name = None

    def test_func(self):
        user_account = self.request.user.account()
        try:
            identity_verified = user_account.identity_verified()
        except stripe.error.StripeError as e:
            if "that account does not exist" in e.message:
                messages.warning(self.request, 'stripe_account_error')
            return None
        return identity_verified


class BankAccountTestsMixin(UserPassesTestMixin):
    login_url = reverse_lazy('terms')
    redirect_field_name = None

    def test_func(self):
        # settting the login_url determines redirect if test returns false
        if self.request.user.accepted_terms():
            self.login_url = self.reverse_lazy_with_param('identity')
        else:
            self.login_url = self.reverse_lazy_with_param('terms')
            return False

        user_account = self.request.user.account()
        try:
            identity_verified = user_account.identity_verified()
        except stripe.error.StripeError as e:
            if "that account does not exist" in e.message:
                messages.warning(self.request, 'stripe_account_error')
            return None
        return identity_verified


class CreditCardView(TemplateView):
    template_name = 'credit_card_page.html'

    def get_context_data(self, **kwargs):
        ctx = super(CreditCardView, self).get_context_data(**kwargs)
        ctx['STRIPE_DEBUG'] = stripe_debug_values()
        return ctx


class CodesyRedirectView(TemplateView):

    def reverse_lazy_with_param(self, template_name):
        request_dict = self.request.GET or self.request.POST
        return_param = urllib.urlencode(request_dict)
        return '%s?%s' % (reverse_lazy(template_name), return_param)

    def get_context_data(self, **kwargs):
        ctx = super(TemplateView, self).get_context_data(**kwargs)
        ctx['return_url'] = self.request.GET.get('return_url', '')
        return ctx

    def post(self, *args, **kwargs):
        return redirect(self.reverse_lazy_with_param('bank'))


class BankAccountView(BankAccountTestsMixin, CodesyRedirectView):
    template_name = 'bank_account_page.html'

    def get_context_data(self, **kwargs):
        ctx = super(BankAccountView, self).get_context_data(**kwargs)
        ctx['STRIPE_DEBUG'] = stripe_debug_values()
        return ctx


class AcceptTermsView(CodesyRedirectView):
    template_name = "accept_terms.html"

    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    def post(self, *args, **kwargs):
        try:
            user = User.objects.get(id=self.request.user.id)
            user.tos_acceptance_date = timezone.now()
            user.tos_acceptance_ip = self.get_client_ip(self.request)
            user.save()
        except User.DoesNotExist:
            pass
        return super(AcceptTermsView, self).post(**kwargs)


class VerifyIdentityView(CodesyRedirectView):
    template_name = 'verify_identity.html'
    identity_fields = ('first_name', 'last_name', 'ssn_last_4',
                       'personal_id_number', 'type', 'business_name',
                       'business_tax_id')
    address_fields = ('line1', 'city', 'postal_code', 'state', )
    dob_fields = ('day', 'month', 'year',)

    def get_context_data(self, **kwargs):
        ctx = super(VerifyIdentityView, self).get_context_data(**kwargs)
        ctx['STRIPE_DEBUG'] = stripe_debug_values()
        codesy_account = self.request.user.account()
        ctx['fields_needed'] = codesy_account.fields_needed
        return ctx

    def post(self, *args, **kwargs):
        codesy_account = self.request.user.account()
        # TODO: Cannot change if account already verified

        if codesy_account:
            posted = self.request.POST
            stripe_acct = stripe.Account.retrieve(codesy_account.account_id)

            for field in self.identity_fields:
                if field in posted:
                    stripe_acct.legal_entity[field] = posted[field]

            for field in self.address_fields:
                if field in posted:
                    stripe_acct.legal_entity.address[field] = posted[field]

            for field in self.dob_fields:
                if field in posted:
                    stripe_acct.legal_entity.dob[field] = posted[field]

            stripe_acct.save()

        return super(VerifyIdentityView, self).post(**kwargs)


class StripeHookView(CSRFExemptMixin, View):

    def post(self, *args, **kwargs):
        message = json.loads(self.request.body)
        event_id = message['id']

        if not StripeEvent.objects.filter(event_id=event_id).exists():
            new_event = StripeEvent(event_id=event_id, message_text=message)
            new_event.save()

        return HttpResponse()