from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import braintree
from django.utils import timezone
import datetime
from django.conf import settings
import sys
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')

from rowers.utils import myqueue
from rowers.tasks import (
    handle_send_email_transaction,
    handle_send_email_subscription_update,
    handle_send_email_subscription_create,
    handle_send_email_failed_cancel,
    )

import pandas as pd

from rowsandall_app.settings import (
    BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY,
    BRAINTREE_SANDBOX_MERCHANT_ID,BRAINTREE_SANDBOX_PUBLIC_KEY,
    BRAINTREE_SANDBOX_PRIVATE_KEY, BRAINTREE_MERCHANT_ACCOUNT_ID
    )

if settings.DEBUG  or 'dev' in settings.SITE_URL:
    gateway = braintree.BraintreeGateway(
        braintree.Configuration(
            braintree.Environment.Sandbox,
            merchant_id=BRAINTREE_SANDBOX_MERCHANT_ID,
            public_key=BRAINTREE_SANDBOX_PUBLIC_KEY,
            private_key=BRAINTREE_SANDBOX_PRIVATE_KEY,
        )
    )
else:
    gateway = braintree.BraintreeGateway(
        braintree.Configuration(
            braintree.Environment.Production,
            merchant_id=BRAINTREE_MERCHANT_ID,
            public_key=BRAINTREE_PUBLIC_KEY,
            private_key=BRAINTREE_PRIVATE_KEY,
        )
    )


from rowers.models import Rower,PaidPlan, CoachingGroup
from rowers.utils import ProcessorCustomerError

def create_customer(rower,force=False):
    if not rower.customer_id or force:
        result = gateway.customer.create(
            {
                'first_name':rower.user.first_name,
                'last_name':rower.user.last_name,
                'email':rower.user.email,
                })
        if not result.is_success:
            raise ProcessorCustomerError
        else:
            rower.customer_id = result.customer.id
            rower.paymentprocessor = 'braintree'
            rower.save()
            return rower.customer_id
    else:
        return rower.customer_id



def get_client_token(rower):
    try:
        client_token = gateway.client_token.generate({
            "customer_id":rower.customer_id,
        })
    except ValueError:
        customer_id = create_customer(rower,force=True)

        client_token = gateway.client_token.generate({
            "customer_id": customer_id,
        })

    return client_token

def get_plans_costs():
    plans = gateway.plan.all()

    localplans = PaidPlan.object.filter(paymentprocessor='braintree')

    for plan in localplans:
        for btplan in btplans:
            if int(btplan.id) == plan.external_id:
                plan.price = float(x)
                plan.save()

    return plans

def make_payment(rower,data):
    nonce_from_the_client = data['payment_method_nonce']
    nonce = gateway.payment_method_nonce.find(nonce_from_the_client)
    info = nonce.three_d_secure_info
    if info is None or not info.liability_shifted:
        return False,0

    amount = data['amount']
    amount = '{amount:.f2}'.format(amount=amount)

    result = gateway.transaction.sale({
        "amount": amount,
        "payment_method_nonce": nonce_from_the_client,
        "options": {
            "submit_for_settlement": True
        }
    })
    if result.is_success:
        transaction = result.transaction
        amount = transaction.amount
        name = '{f} {l}'.format(
            f = rower.user.first_name,
            l = rower.user.last_name,
            )


        job = myqueue(queuehigh,handle_send_email_transaction,
                      name, rower.user.email, amount)

        return amount,''
    else:
        return 0,''

def update_subscription(rower,data,method='up'):
    planid = data['plan']
    plan = PaidPlan.objects.get(id=planid)
    nonce_from_the_client = data['payment_method_nonce']
    nonce = gateway.payment_method_nonce.find(nonce_from_the_client)
    info = nonce.three_d_secure_info
    if info is None or not info.liability_shifted:
        return False,0
    amount = data['amount']
    amount = '{amount:.2f}'.format(amount=amount)


    gatewaydata = {
            "price": amount,
            "plan_id": plan.external_id,
            "payment_method_nonce": nonce_from_the_client,
            "options": {
                "prorate_charges":True,
                },
            }


    if plan.paymenttype == 'single':
        gatewaydata['number_of_billing_cycles'] = 1
    else:
        gatewaydata['never_expires'] = True

    try:
        result = gateway.subscription.update(
            rower.subscription_id,
            gatewaydata
        )
    except:
        return False,0

    if result.is_success:
        yesterday = (timezone.now()-datetime.timedelta(days=1)).date()
        rower.paidplan = plan
        rower.planexpires = result.subscription.billing_period_end_date
        rower.teamplanexpires = result.subscription.billing_period_end_date
        rower.clubsize = plan.clubsize
        rower.paymenttype = plan.paymenttype
        rower.rowerplan = plan.shortname
        rower.subscription_id = result.subscription.id
        rower.protrialexpires = yesterday
        rower.plantrialexpires = yesterday
        rower.save()
        name = '{f} {l}'.format(
            f = rower.user.first_name,
            l = rower.user.last_name,
            )

        if rower.paidplan != 'coach':
            try:
                coachgroup = rower.mycoachgroup
            except CoachingGroup.DoesNotExist:
                coachgroup = CoachingGroup()
                coachgroup.save()
                rower.mycoachgroup = coachgroup
                rower.save()

            athletes = Rower.objects.filter(coachinggroups__in=[rower.mycoachgroup]).distinct()
            for athlete in athletes:
                athlete.coachinggroups.remove(rower.mycoachgroup)

        if method == 'up':
            transactions = result.subscription.transactions

            if transactions:
                amount = transactions[0].amount
            else:
                amount = 0
        else:
            amount = 0


        job = myqueue(queuehigh,
                      handle_send_email_subscription_update,
                      name, rower.user.email,
                      plan.name,
                      plan.paymenttype,
                      plan.price,
                      amount,
                      result.subscription.billing_period_end_date.strftime('%Y-%m-%d'),
                      method)

        return True,amount
    else:
        errors = result.errors.for_object("subscription")
        codes = [str(e.code) for e in errors]
        create_new = False
        proceed_codes = ['81901','81910']
        for c in codes:
            if c in proceed_codes:
                create_new = True

        if create_new:
            return create_subscription(rower,data)

        return False,0

    return False,0


def create_subscription(rower,data):
    nonce_from_the_client = data['payment_method_nonce']
    nonce = gateway.payment_method_nonce.find(nonce_from_the_client)
    info = nonce.three_d_secure_info
    paymenttype = nonce.type

    if nonce.type != 'PayPalAccount':
        if info is None  or not info.liability_shifted:
            return False,0
    amount = data['amount']

    planid = data['plan']
    plan = PaidPlan.objects.get(id=planid)


    # create or find payment method
    result = gateway.payment_method.create({
        "customer_id": rower.customer_id,
        "payment_method_nonce": nonce_from_the_client
        })

    if result.is_success:
        payment_method_token = result.payment_method.token
    else:
        return False,0

    result = gateway.subscription.create({
        "payment_method_token": payment_method_token,
        "plan_id": plan.external_id,
#        "merchant_account_id": BRAINTREE_MERCHANT_ACCOUNT_ID,
        })


    if result.is_success:
        yesterday = (timezone.now()-datetime.timedelta(days=1)).date()
        rower.paidplan = plan
        rower.planexpires = result.subscription.billing_period_end_date
        rower.teamplanexpires = result.subscription.billing_period_end_date
        rower.clubsize = plan.clubsize
        rower.paymenttype = plan.paymenttype
        rower.rowerplan = plan.shortname
        rower.subscription_id = result.subscription.id
        rower.protrialexpires = yesterday
        rower.plantrialexpires = yesterday

        rower.save()
        name = '{f} {l}'.format(
            f = rower.user.first_name,
            l = rower.user.last_name,
            )


        recurring = plan.paymenttype

        job = myqueue(
            queuehigh,
            handle_send_email_subscription_create,
            name, rower.user.email,
            plan.name,
            recurring,
            plan.price,
            plan.price,
            result.subscription.billing_period_end_date.strftime('%Y-%m-%d')
        )
        return True,plan.price
    else:
        return False,0


    return False,0

def cancel_subscription(rower,id):
    themessages = []
    errormessages = []
    try:
        result =  gateway.subscription.cancel(id)
        themessages.append("Subscription canceled")
    except:
        errormessages.append("We could not find the subscription record in our customer database. We have notified the site owner, who will contact you.")


        name = '{f} {l}'.format(f = rower.user.first_name, l = rower.user.last_name)


        job = myqueue(queuehigh,
                      handle_send_email_failed_cancel,
                      name, rower.user.email,rower.user.username,id)

        return False, themessages, errormessages

    basicplans = PaidPlan.objects.filter(price=0,paymentprocessor='braintree')
    rower.paidplan = basicplans[0]
    rower.teamplanexpires = timezone.now()
    rower.planexpires = timezone.now()
    rower.clubsize = 0
    rower.rowerplan = 'basic'
    rower.subscription_id = None
    rower.save()
    themessages.append("Your plan was reset to basic")

    return True, themessages,errormessages


def find_subscriptions(rower):
    try:
        result = gateway.customer.find(rower.customer_id)
    except:
        raise ProcessorCustomerError("We could not find the customer in the database")

    active_subscriptions = []

    cards = result.credit_cards
    for card in cards:
        for subscription in card.subscriptions:
            if subscription.status == 'Active':
                active_subscriptions.append(subscription)

    try:
        paypal_accounts = result.paypal_accounts
        for account in paypal_accounts:
            for subscription in account.subscriptions:
                if subscription.status == 'Active':
                    active_subscriptions.append(subscription)
    except AttributeError:
        pass

    result = []

    for subscription in active_subscriptions:

        plan = PaidPlan.objects.filter(paymentprocessor="braintree",
                                       external_id=subscription.plan_id)[0]

        thedict = {
            'end_date': subscription.billing_period_end_date,
            'plan_id': subscription.plan_id,
            'price': subscription.price,
            'id': subscription.id,
            'plan': plan.name,
            'never_expires': subscription.never_expires
            }

        result.append(thedict)

    return result

def get_transactions(start_date,end_date):
    results = gateway.transaction.search(
        braintree.TransactionSearch.created_at.between(
            start_date,
            end_date,
            )
        )

    amounts = []
    countries = []
    addresses = []
    card_countries = []
    names = []
    emails = []
    dates = []
    currencies = []
    statuses = []
    ids = []
    usernames = []
    customerids = []
    transactionids = []
    subscriptionids = []
    ownids = []

    countlines = [1 for transaction in results]

    for transaction in results:
        r = None
        rs = Rower.objects.filter(
            customer_id=transaction.customer['id'],
            paymentprocessor='braintree')
        if rs:
            r = rs[0]
            countries.append(r.country)
            addresses.append('{street}, {city}, {postal_code}'.format(
                street = r.street_address,
                city = r.city,
                postal_code = r.postal_code))
            ownids.append(r.id)
            usernames.append(r.user.username)

        else:
            countries.append(
                transaction.credit_card_details.country_of_issuance)
            ownids.append('unknown')
            usernames.append('unknown')
            addresses.append('')


        emails.append(transaction.customer_details.email)
        names.append('{f} {l}'.format(
            f = transaction.customer['first_name'],
            l = transaction.customer['last_name']
        )
        )
        customerids.append(transaction.customer['id'])
        transactionids.append(transaction.id)
        subscriptionids.append(transaction.subscription_id)
        amounts.append(transaction.amount)
        dates.append(transaction.created_at)
        currencies.append(transaction.currency_iso_code)
        card_countries.append(
            transaction.credit_card_details.country_of_issuance)
        statuses.append(transaction.status)


    df = pd.DataFrame({
        'name':names,
        'email':emails,
        'date':dates,
        'amount':amounts,
        'currency':currencies,
        'country':countries,
        'card_country':card_countries,
        'status':statuses,
        'username':usernames,
        'user_id':ownids,
        'customer_id':customerids,
        'transaction_id':transactionids,
        'subscription_id':subscriptionids,
        'address':addresses
    }
    )

    return df


def mocktest(rower):
    return '5'
