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, Order, Coupon
from core import CoffeeGrind
from storefront.forms import AddressForm, OrderCreateForm
from storefront.views import (
    CartView, CartAddProductView, CartUpdateProductView, CouponApplyView,
    ProductListView, ProductDetailView,
    CheckoutAddressView, OrderCreateView,
    paypal_order_transaction_capture, paypal_webhook_endpoint,
    PaymentDoneView, PaymentCanceledView,
    CustomerDetailView, CustomerUpdateView, OrderDetailView,
    CustomerAddressCreateView, CustomerAddressUpdateView,
    AboutView, FairTradeView, ReviewListView,
)
from storefront.cart import Cart

logger = logging.getLogger(__name__)


class CartViewTest(TestCase):
    fixtures = ['products.json']

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/cart/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:cart-detail'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:cart-detail'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/cart_detail.html')


class CheckoutAddressViewTest(TestCase):
    def setUp(self):
        self.client = Client()

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:checkout-address'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/checkout_address.html')

    def test_view_has_correct_form(self):
        response = self.client.get(reverse('storefront:checkout-address'))
        self.assertTrue(response.context['form'])
        self.assertTrue(isinstance(response.context['form'], AddressForm))


class OrderCreateViewTest(TestCase):
    fixtures = ['accounts.json', 'coupons.json']

    @classmethod
    def setUpTestData(cls):
        cls.customer = User.objects.get(pk=1)
        cls.product = Product.objects.create(
            name="Dante's Tornado",
            description='Coffee',
            sku='23987',
            price=13.4,
            weight=Weight(oz=16),
            visible_in_listings=True
        )
        cls.order = Order.objects.create(
            customer=cls.customer,
            total_net_amount=13.4
        )

    def setUp(self):
        self.client = Client()
        session = self.client.session
        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'
        }
        session.save()

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/checkout/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:order-create')
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:order-create')
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/order_form.html')

    def test_used_coupon_creates_error_on_checkout(self):
        session = self.client.session
        session['coupon_code'] = 'MAY2022'
        session.save()

        response = self.client.get(
            reverse('storefront:order-create'), follow=True
        )
        self.assertTrue(self.client.session.get('shipping_address'))
        self.assertTemplateUsed(response, 'storefront/order_form.html')
        self.assertContains(response, 'Coupon already used', status_code=200)


class ProductListViewTest(TestCase):
    fixtures = ['products.json']

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:product-list'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:product-list'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/product_list.html')


class ProductDetailViewTest(TestCase):
    fixtures = ['products.json']

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/products/1/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:product-detail', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:product-detail', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/product_detail.html')


class CheckoutAddressViewTest(TestCase):
    fixtures = ['products.json']

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/checkout/address/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:checkout-address'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:checkout-address'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/checkout_address.html')


class OrderCreateViewTest(TestCase):
    fixtures = ['products.json']

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


class PaymentDoneViewTest(TestCase):
    fixtures = ['products.json']

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/done/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:payment-done'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:payment-done'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/payment_done.html')


class PaymentCanceledViewTest(TestCase):
    fixtures = ['products.json']

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/canceled/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:payment-canceled'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:payment-canceled'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/payment_canceled.html')


class CustomerDetailViewTest(TestCase):
    fixtures = ['products.json', 'accounts.json']

    def setUp(self):
        self.client = Client()
        self.user = User.objects.get(pk=1)
        self.client.force_login(self.user)

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/customers/1/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:customer-detail', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:customer-detail', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/customer_detail.html')


class CustomerUpdateViewTest(TestCase):
    fixtures = ['products.json', 'accounts.json']

    def setUp(self):
        self.client = Client()
        self.user = User.objects.get(pk=1)
        self.client.force_login(self.user)

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/customers/1/update/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:customer-update', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:customer-update', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/customer_form.html')


class OrderDetailViewTest(TestCase):
    fixtures = ['products.json', 'accounts.json', 'orders.json']

    def setUp(self):
        self.client = Client()
        self.user = User.objects.get(pk=1)
        self.client.force_login(self.user)

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/customers/1/orders/1/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:order-detail', kwargs={'pk': 1, 'order_pk': 1})
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:order-detail', kwargs={'pk': 1, 'order_pk': 1})
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/order_detail.html')


class CustomerAddressCreateViewTest(TestCase):
    fixtures = ['products.json', 'accounts.json']

    def setUp(self):
        self.client = Client()
        self.user = User.objects.get(pk=1)
        self.client.force_login(self.user)

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/customers/1/addresses/new/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:customer-address-create', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:customer-address-create', kwargs={'pk': 1})
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(
            response, 'storefront/address_create_form.html'
        )


class CustomerAddressUpdateViewTest(TestCase):
    fixtures = ['products.json', 'accounts.json']

    def setUp(self):
        self.client = Client()
        self.user = User.objects.get(pk=1)
        self.client.force_login(self.user)

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/customers/1/addresses/1/update/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('storefront:address-update', kwargs={
                'pk': 1, 'address_pk': 1
            })
        )
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(
            reverse('storefront:address-update', kwargs={
                'pk': 1, 'address_pk': 1}
            )
        )
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/address_form.html')


class AboutViewTest(TestCase):

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

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/about/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:about'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:about'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/about.html')


class FairTradeViewTest(TestCase):
    def setUp(self):
        self.client = Client()

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/fair-trade/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:fair-trade'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:fair-trade'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/fairtrade.html')


class ReviewListViewTest(TestCase):
    def setUp(self):
        self.client = Client()

    def test_view_url_exists_at_desired_location(self):
        response = self.client.get('/reviews/')
        self.assertEqual(response.status_code, 200)

    def test_view_url_accessible_by_name(self):
        response = self.client.get(reverse('storefront:reviews'))
        self.assertEqual(response.status_code, 200)

    def test_view_uses_correct_template(self):
        response = self.client.get(reverse('storefront:reviews'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'storefront/reviews.html')
