import logging
from decimal import Decimal

from django.test import TestCase, Client, RequestFactory
from django.urls import reverse
from django.conf import settings
from measurement.measures import Weight
from paypalcheckoutsdk.orders import OrdersCreateRequest, OrdersCaptureRequest
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment

from accounts.models import User, Address
from core.models import Product, ProductVariant, Order
from core import CoffeeGrind
from storefront.views import OrderCreateView
from storefront.cart import CartItem, Cart

logger = logging.getLogger(__name__)


class CartItemTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.customer = User.objects.create_user(
            username='petertempler',
            email='peter@testing.com',
            password='peterspassword321'
        )
        cls.product = Product.objects.create(
            name="Dante's Tornado",
            subtitle='Medium Roast',
            description='Coffee',
            checkout_limit=10,
            visible_in_listings=True
        )
        cls.variant_1 = ProductVariant.objects.create(
            product=cls.product,
            name='12 oz',
            sku='234987',
            price=Decimal('12.00'),
            weight=Weight(oz=12),
        )
        cls.variant_2 = ProductVariant.objects.create(
            product=cls.product,
            name='16 oz',
            sku='987621',
            price=Decimal('16.00'),
            weight=Weight(oz=16),
        )
        cls.variant_3 = ProductVariant.objects.create(
            product=cls.product,
            name='16 oz',
            sku='65432',
            price=Decimal('75.00'),
            weight=Weight(lb=5),
        )
        cls.order = Order.objects.create(
            customer=cls.customer,
            total_amount=Decimal('13.40')
        )

    def setUp(self):
        self.client = Client()
        self.factory = RequestFactory()

        self.client.force_login(self.customer)
        self.client.session['shipping_address'] = {
            'first_name': 'Nathan',
            'last_name': 'Chapman',
            'email': 'contact@nathanjchapman.com',
            'street_address_1': '1504 N 230 E',
            'street_address_2': '',
            'city': 'North Logan',
            'state': 'UT',
            'postal_code': '84341'
        }

    def test_calculates_total_weight(self):
        cart_item = CartItem({
            'variant_pk': self.variant_1.pk,
            'quantity': 14,
            'options': {'Grind': 'Whole Beans'}
        })
        self.assertEqual(
            cart_item.total_price,
            Decimal('168.00')
        )

    def test_calculates_total_price(self):
        cart_item = CartItem({
            'variant_pk': self.variant_1.pk,
            'quantity': 14,
            'options': {'Grind': 'Whole Beans'}
        })
        self.assertEqual(
            cart_item.total_weight,
            Weight(lb=10.5)
        )


class CartTest(TestCase):
    fixtures = ['site_settings_and_shipping_rates.json']

    @classmethod
    def setUpTestData(cls):
        cls.customer = User.objects.create_user(
            username='petertempler',
            email='peter@testing.com',
            password='peterspassword321'
        )
        cls.product = Product.objects.create(
            name="Dante's Tornado",
            subtitle='Medium Roast',
            description='Coffee',
            checkout_limit=10,
            visible_in_listings=True
        )
        cls.variant = ProductVariant.objects.create(
            product=cls.product,
            name='16 oz',
            sku='234987',
            price=Decimal('13.40'),
            weight=Weight(oz=16),
        )
        cls.order = Order.objects.create(
            customer=cls.customer,
            total_amount=Decimal('13.40')
        )

    def setUp(self):
        self.client = Client()
        self.factory = RequestFactory()
        self.client.force_login(self.customer)

    def test_cart_item_variations(self):
        cart_detail_url = reverse('storefront:cart-detail')
        response = self.client.get(cart_detail_url, follow=True)
        logger.debug(response.context['messages'])
        request = response.wsgi_request
        cart = Cart(request)

        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 1,
                'options': {'Grind': 'Whole Beans'}
            })
        )
        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 1,
                'options': {'Grind': 'Espresso'}
            })
        )
        for item in cart:
            self.assertTrue(hasattr(item, 'variant'))

    def test_add_item_to_cart(self):
        cart_detail_url = reverse('storefront:cart-detail')
        response = self.client.get(cart_detail_url)
        request = response.wsgi_request
        request.session['shipping_address'] = {
            'first_name': 'Nathan',
            'last_name': 'Chapman',
            'email': 'contact@nathanjchapman.com',
            'street_address_1': '1504 N 230 E',
            'street_address_2': '',
            'city': 'North Logan',
            'state': 'UT',
            'postal_code': '84341'
        }
        cart = Cart(request)

        cart = Cart(request)
        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 1,
                'options': {'Grind': 'Whole Beans'}
            })
        )

        self.assertEqual(
            cart.items[0].quantity,
            1
        )
        self.assertEqual(len(cart), 1)
        self.assertEqual(cart.total_weight, Weight(lb=1))
        self.assertEqual(cart.subtotal_price, Decimal('13.40'))
        self.assertEqual(cart.total_price, cart.get_shipping_price() + Decimal('13.40'))
        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 1,
                'options': {'Grind': 'Whole Beans'}
            })
        )
        self.assertEqual(
            cart.items[0].quantity,
            2
        )
        self.assertEqual(len(cart), 2)

        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 3,
                'options': {'Grind': 'Espresso'}
            })
        )
        self.assertEqual(
            cart.items[1].quantity,
            3
        )
        self.assertEqual(len(cart), 5)
        self.assertEqual(cart.total_weight, Weight(lb=5))
        self.assertEqual(cart.subtotal_price, Decimal('67.00'))
        self.assertEqual(cart.total_price, cart.get_shipping_price() + Decimal('67.00'))

    def test_update_cart_item_quantity(self):
        cart_detail_url = reverse('storefront:cart-detail')
        response = self.client.get(cart_detail_url)
        request = response.wsgi_request
        cart = Cart(request)

        cart = Cart(request)
        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 3,
                'options': {'Grind': 'Whole Beans'}
            })
        )
        self.assertEqual(
            cart.items[0].quantity,
            3
        )

        cart.update_item_quantity(0, 1)
        self.assertEqual(
            cart.items[0].quantity,
            1
        )

    def test_cart_remove_item(self):
        cart_detail_url = reverse('storefront:cart-detail')
        response = self.client.get(cart_detail_url)
        request = response.wsgi_request
        cart = Cart(request)

        cart = Cart(request)
        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 3,
                'options': {'Grind': 'Whole Beans'}
            })
        )
        self.assertEqual(len(cart), 3)
        cart.remove_item(0)
        self.assertEqual(len(cart), 0)

    def test_cart_total_weight(self):
        cart_detail_url = reverse('storefront:cart-detail')
        response = self.client.get(cart_detail_url)
        request = response.wsgi_request
        cart = Cart(request)

        cart = Cart(request)
        cart.add_item(
            CartItem({
                'variant_pk': self.variant.pk,
                'quantity': 3,
                'options': {'Grind': 'Whole Beans'}
            })
        )
        self.assertEqual(cart.total_weight, Weight(lb=3))
