import decimal
from unittest import mock

from django.conf import settings
from django.test import modify_settings
from rest_framework import test
from rest_framework.reverse import reverse
import stripe

from restshop import serializers
from restshop.models import Order
from paymentmethods.stripejs.models import StripeInvoice
import restshop.exceptions
from restshop.tests.test_product import products_and_price


@modify_settings(INSTALLED_APPS={
    'append': 'restshop.paymentmethods.stripejs'
})
class StripeTest(test.APITestCase):

    def setUp(self):
        stripe.api_key = settings.STRIPE_API_KEY
        self.order = Order.objects.create(
            email='tester@test.com',
        )
        self.order.items.create(
            description='test purchase',
            price='1000',
            vat='250',
            quantity=3,
            product=products_and_price(1000).skus.all()[0]
        )
        session = self.client.session
        session['order_id'] = self.order.pk
        session.save()

    def get_token(self):
        return stripe.Token.create(card={
            "number": '4242424242424242',
            "exp_month": 12,
            "exp_year": 2016,
            "cvc": '123'
        }).id

    def test_pay(self):
        response = self.client.post(
            reverse(
                'order-pay',
                args=['stripejs.stripeinvoice']
            ),
            {
                'stripeToken': self.get_token(),
                'order': serializers.OrderSerializer(instance=self.order).data
            }
        )
        self.assertEqual(201, response.status_code, response.data)
        self.assertEqual(0,
                         decimal.Decimal(response.data['owed']) -
                         decimal.Decimal(response.data['paid']))
        order = Order.objects.get()
        self.assertEqual(
            Order.STATUS.completed,
            order.status
        )
        self.assertEqual(
            decimal.Decimal('3750.00'),
            order.invoices.all()[0].paid
        )

    @mock.patch('stripe.Charge.create')
    def test_card_error(self, create_mock):
        create_mock.side_effect = stripe.CardError('fail!', '', '402')
        si = StripeInvoice.objects.create(
            order=self.order,
            owed=self.order.amount,
            stripeToken=self.get_token(),
        )
        try:
            si.authorize()
        except restshop.exceptions.PaymentFailed as e:
            self.assertEqual('fail!', e.detail)
        else:
            self.assertRaises(restshop.exceptions.PaymentFailed, lambda: None)

    def test_cancel_auth(self):
        si = StripeInvoice.objects.create(
            order=self.order,
            owed=self.order.amount,
            stripeToken=self.get_token(),
        )
        self.assertRaises(
            restshop.exceptions.InvalidOperation,
            si.cancel_auth
        )
        self.assertTrue(si.authorize())
        self.assertTrue(si.cancel_auth())
        si.refresh_from_db()
        self.assertEqual(2, si.events.all().count())
        self.assertEqual(StripeInvoice.STATUS.canceled, si.status)

[((17, 1, 19, 2), 'django.test.modify_settings', 'modify_settings', (), '', False, 'from django.test import modify_settings\n'), ((71, 5, 71, 39), 'unittest.mock.patch', 'mock.patch', ({(71, 16, 71, 38): '"""stripe.Charge.create"""'}, {}), "('stripe.Charge.create')", False, 'from unittest import mock\n'), ((24, 21, 26, 9), 'restshop.models.Order.objects.create', 'Order.objects.create', (), '', False, 'from restshop.models import Order\n'), ((61, 16, 61, 35), 'restshop.models.Order.objects.get', 'Order.objects.get', ({}, {}), '()', False, 'from restshop.models import Order\n'), ((73, 34, 73, 70), 'stripe.CardError', 'stripe.CardError', ({(73, 51, 73, 58): '"""fail!"""', (73, 60, 73, 62): '""""""', (73, 64, 73, 69): '"""402"""'}, {}), "('fail!', '', '402')", False, 'import stripe\n'), ((39, 15, 44, 10), 'stripe.Token.create', 'stripe.Token.create', (), '', False, 'import stripe\n'), ((48, 12, 51, 13), 'rest_framework.reverse.reverse', 'reverse', (), '', False, 'from rest_framework.reverse import reverse\n'), ((67, 12, 67, 38), 'decimal.Decimal', 'decimal.Decimal', ({(67, 28, 67, 37): '"""3750.00"""'}, {}), "('3750.00')", False, 'import decimal\n'), ((59, 25, 59, 63), 'decimal.Decimal', 'decimal.Decimal', ({(59, 41, 59, 62): "response.data['owed']"}, {}), "(response.data['owed'])", False, 'import decimal\n'), ((60, 25, 60, 63), 'decimal.Decimal', 'decimal.Decimal', ({(60, 41, 60, 62): "response.data['paid']"}, {}), "(response.data['paid'])", False, 'import decimal\n'), ((54, 25, 54, 73), 'restshop.serializers.OrderSerializer', 'serializers.OrderSerializer', (), '', False, 'from restshop import serializers\n'), ((32, 20, 32, 44), 'restshop.tests.test_product.products_and_price', 'products_and_price', ({(32, 39, 32, 43): '(1000)'}, {}), '(1000)', False, 'from restshop.tests.test_product import products_and_price\n')]