import logging
import requests
from django.conf import settings
from django.shortcuts import render, reverse, redirect, get_object_or_404
from django.urls import reverse_lazy
from django.core.mail import EmailMessage
from django.http import JsonResponse
from django.views.generic.base import RedirectView, TemplateView
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView, FormMixin
from django.views.generic.detail import DetailView, SingleObjectMixin
from django.views.generic.list import ListView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

from paypalcheckoutsdk.orders import OrdersCreateRequest, OrdersCaptureRequest
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment

from accounts.models import User, Address
from accounts.utils import get_or_create_customer
from core.models import Product, Order, Transaction, OrderLine
from core.forms import ShippingMethodForm

from .forms import AddToCartForm, OrderCreateForm, AddressForm
from .cart import Cart

logger = logging.getLogger(__name__)

class CartView(TemplateView):
    template_name = 'storefront/cart_detail.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        cart = Cart(self.request)
        for item in cart:
            item['update_quantity_form'] = AddToCartForm(
                initial={
                    'quantity': item['quantity'],
                    'roast': item['roast'],
                    'other': item['other'],
                    'update': True
                }
            )
        context['cart'] = cart
        return context

class CartAddProductView(SingleObjectMixin, FormView):
    model = Product
    form_class = AddToCartForm

    def get_success_url(self):
        return reverse('storefront:cart-detail')

    def post(self, request, *args, **kwargs):
        cart = Cart(request)
        form = self.get_form()
        if form.is_valid():
            cart.add(
                product=self.get_object(),
                roast=form.cleaned_data['roast'],
                other=form.cleaned_data['other'],
                quantity=form.cleaned_data['quantity'],
                update_quantity=form.cleaned_data['update']
            )
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        return super().form_valid(form)


def cart_remove_product_view(request, pk):
    cart = Cart(request)
    product = get_object_or_404(Product, id=pk)
    cart.remove(product)
    return redirect('storefront:cart-detail')


class ProductListView(FormMixin, ListView):
    model = Product
    template_name = 'storefront/product_list.html'
    form_class = AddToCartForm

    queryset = Product.objects.filter(
        visible_in_listings=True
    )


class ProductDetailView(FormMixin, DetailView):
    model = Product
    template_name = 'storefront/product_detail.html'
    form_class = AddToCartForm

def paypal_order_transaction_capture(request, transaction_id):
    if request.method =="POST":
        capture_order = OrdersCaptureRequest(transaction_id)
        environment = SandboxEnvironment(client_id=settings.PAYPAL_CLIENT_ID, client_secret=settings.PAYPAL_SECRET_ID)
        client = PayPalHttpClient(environment)

        response = client.execute(capture_order)
        data = response.result.__dict__['_dict']
        data['redirect_urls'] = {
            'return_url': request.build_absolute_uri(reverse_lazy('storefront:payment-done')),
            'cancel_url': request.build_absolute_uri(reverse_lazy('storefront:payment-canceled'))
        }
        transaction = Transaction.objects.get(order__pk=request.session.get('order_id'))
        transaction.paypal_id = data['purchase_units'][0]['payments']['captures'][0]['id']
        transaction.status = data['status']
        transaction.save()
        logger.debug(f'\nPayPal Response data: {data}\n')

        return JsonResponse(data)
    else:
        return JsonResponse({'details': 'invalid request'})


class CheckoutAddressView(FormView):
    template_name = 'storefront/checkout_address.html'
    form_class = AddressForm
    success_url = reverse_lazy('storefront:order-create')

    def get_initial(self):
        user = self.request.user
        initial = None
        if user.is_authenticated and user.default_shipping_address:
            address = user.default_shipping_address
            initial = {
                'first_name': address.first_name,
                'last_name': address.last_name,
                'email': user.email,
                'street_address_1': address.street_address_1,
                'street_address_2': address.street_address_2,
                'city': address.city,
                'state': address.state,
                'postal_code': address.postal_code
            }
        return initial

    def form_valid(self, form):
        # save address data to session
        self.request.session['shipping_address'] = form.cleaned_data
        return super().form_valid(form)

class OrderCreateView(CreateView):
    model = Order
    template_name = 'storefront/order_form.html'
    form_class = OrderCreateForm
    success_url = reverse_lazy('storefront:payment-done')

    def get_initial(self):
        cart = Cart(self.request)
        initial = {
            'total_net_amount': cart.get_total_price()
        }

        if self.request.user.is_authenticated:
            user_info = {
                'email': self.request.user.email,
                'first_name': self.request.user.first_name,
                'last_name': self.request.user.last_name,
            }
            initial |= user_info
        else:
            a = self.request.session.get('shipping_address')
            user_info = {
                'email': a['email'],
                'first_name': a['first_name'],
                'last_name': a['last_name']
            }
            initial |= user_info

        return initial

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['shipping_address'] = self.request.session.get('shipping_address')
        return context

    def form_valid(self, form):
        shipping_address = self.request.session.get('shipping_address')
        form.instance.customer, form.instance.shipping_address = get_or_create_customer(self.request, form, shipping_address)
        self.object = form.save()

        # Cart data setup
        cart = Cart(self.request)
        bulk_list, body_data = cart.get_bulk_list_and_body_data(self.object, shipping_address)
        logger.debug(f'\nBody data: {body_data}\n')

        # Bulk create OrderLine objects from cart items
        objs = OrderLine.objects.bulk_create(bulk_list)

        # PayPal setup
        environment = SandboxEnvironment(client_id=settings.PAYPAL_CLIENT_ID, client_secret=settings.PAYPAL_SECRET_ID)
        client = PayPalHttpClient(environment)
        create_order = OrdersCreateRequest()
        create_order.request_body(body_data)

        response = client.execute(create_order)
        data = response.result.__dict__['_dict']

        cart.clear()
        self.request.session['order_id'] = self.object.id

        return JsonResponse(data)


class PaymentDoneView(TemplateView):
    template_name = 'storefront/payment_done.html'

class PaymentCanceledView(TemplateView):
    template_name = 'storefront/payment_canceled.html'


class CustomerDetailView(DetailView):
    model = User
    template_name = 'storefront/customer_detail.html'
    context_object_name = 'customer'

class CustomerUpdateView(UpdateView):
    model = User
    template_name = 'storefront/customer_form.html'
    context_object_name = 'customer'
    fields = (
        'first_name',
        'last_name',
        'email',
        'default_shipping_address'
    )

    def get_success_url(self):
        return reverse('storefront:customer-detail', kwargs={'pk': self.object.pk})

class AboutView(TemplateView):
    template_name = 'storefront/about.html'
