import logging
from datetime import datetime
from django.conf import settings
from django.utils import timezone
from django.shortcuts import render, reverse, redirect, get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse, reverse_lazy
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
from django.forms import inlineformset_factory
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin

from django.db.models import (
    Exists, OuterRef, Prefetch, Subquery, Count, Sum, Avg, F, Q, Value
)
from django.db.models.functions import Coalesce

from accounts.models import User
from accounts.utils import get_or_create_customer
from accounts.forms import AddressForm
from core.models import (
    Product,
    ProductPhoto,
    Order,
    OrderLine,
    ShippingMethod,
    Transaction,
    TrackingNumber,
    Coupon
)

from core import (
    DiscountValueType,
    VoucherType,
    OrderStatus,
    ShippingMethodType
)
from .forms import (
    OrderLineFulfillForm,
    OrderLineFormset,
    OrderCancelForm,
    OrderTrackingFormset,
    CouponForm,
    ProductPhotoForm
)

logger = logging.getLogger(__name__)


class DashboardHomeView(LoginRequiredMixin, TemplateView):
    template_name = 'dashboard/dashboard_detail.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        today = timezone.localtime(timezone.now()).date()
        context['order_count'] = Order.objects.exclude(
            status=OrderStatus.DRAFT
        ).filter(
            created_at__date=today
        ).count()
        context['orders_unfulfilled'] = Order.objects.filter(
            status=OrderStatus.UNFULFILLED
        ).count()
        context['todays_sales'] = Order.objects.exclude(
            status=OrderStatus.DRAFT
        ).filter(
            created_at__date=today
        ).aggregate(total=Sum('total_net_amount'))['total']
        return context


class DashboardConfigView(TemplateView):
    template_name = 'dashboard/config.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        today = timezone.localtime(timezone.now()).date()

        context['shipping_method_list'] = ShippingMethod.objects.all()

        return context


class ShippingMethodCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = ShippingMethod
    template_name = 'dashboard/shipmeth_create_form.html'
    fields = '__all__'
    success_message = '%(name)s created.'


class ShippingMethodDetailView(LoginRequiredMixin, DetailView):
    model = ShippingMethod
    template_name = 'dashboard/shipmeth_detail.html'


class CouponListView(LoginRequiredMixin, ListView):
    model = Coupon
    template_name = 'dashboard/coupon_list.html'


class CouponCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = Coupon
    template_name = 'dashboard/coupon_create_form.html'
    form_class = CouponForm
    success_message = '%(name)s created.'


class CouponDetailView(LoginRequiredMixin, DetailView):
    model = Coupon
    template_name = 'dashboard/coupon_detail.html'


class CouponUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Coupon
    template_name = 'dashboard/coupon_form.html'
    success_message = '%(name)s saved.'
    form_class = CouponForm


class CouponDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
    model = Coupon
    template_name = 'dashboard/coupon_confirm_delete.html'
    success_url = reverse_lazy('dashboard:coupon-list')
    success_message = 'Coupon deleted.'


class OrderListView(LoginRequiredMixin, ListView):
    model = Order
    template_name = 'dashboard/order_list.html'
    paginate_by = 50

    def get_queryset(self):
        query = self.request.GET.get('status')
        if query == 'unfulfilled':
            object_list = Order.objects.filter(
                Q(status=OrderStatus.UNFULFILLED) |
                Q(status=OrderStatus.PARTIALLY_FULFILLED)
            ).order_by(
                '-created_at'
            ).select_related(
                'customer'
            )

        else:
            object_list = Order.objects.order_by(
                '-created_at'
            ).select_related(
                'customer'
            )

        return object_list


class OrderDetailView(LoginRequiredMixin, DetailView):
    model = Order
    template_name = 'dashboard/order_detail.html'

    def get_object(self):
        queryset = Order.objects.with_fulfillment_and_filter(
            self.kwargs.get(self.pk_url_kwarg)
        ).select_related(
            'customer',
            'billing_address',
            'shipping_address',
            'shipping_method'
        ).prefetch_related(
            'lines__product__productphoto_set'
        )
        obj = queryset.get()
        return obj

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context


class OrderFulfillView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Order
    template_name = "dashboard/order_fulfill.html"
    form_class = OrderLineFormset
    success_message = "Order saved."

    def form_valid(self, form):
        form.save()
        return HttpResponseRedirect(self.get_success_url())

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


class OrderCancelView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Order
    template_name = "dashboard/order_cancel_form.html"
    form_class = OrderCancelForm
    success_message = "Order canceled."
    initial = {
        'status': OrderStatus.CANCELED
    }

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


class OrderTrackingView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Order
    template_name = "dashboard/order_tracking_form.html"
    form_class = OrderTrackingFormset
    success_message = "Order saved."

    def form_valid(self, form):
        form.save()
        return HttpResponseRedirect(self.get_success_url())

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


class ProductListView(LoginRequiredMixin, ListView):
    model = Product
    template_name = 'dashboard/product_list.html'
    ordering = 'sorting'

    # def get_queryset(self):
    #     object_list = Product.objects.filter(
    #         status=OrderStatus.UNFULFILLED
    #     ).select_related(
    #         'customer'
    #     )
    #     return object_list


class ProductDetailView(LoginRequiredMixin, DetailView):
    model = Product
    template_name = 'dashboard/product_detail.html'


class ProductUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Product
    template_name = 'dashboard/product_update_form.html'
    fields = '__all__'
    success_message = '%(name)s saved.'


class ProductCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = Product
    template_name = 'dashboard/product_create_form.html'
    fields = '__all__'
    success_message = '%(name)s created.'


class ProductDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
    model = Product
    template_name = 'dashboard/product_confirm_delete.html'
    success_url = reverse_lazy('dashboard:product-list')
    success_message = 'Product deleted.'


class ProductPhotoCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = ProductPhoto
    pk_url_kwarg = 'photo_pk'
    template_name = 'dashboard/prodphoto_create_form.html'
    form_class = ProductPhotoForm
    success_message = 'Photo added.'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['product'] = Product.objects.get(pk=self.kwargs['pk'])
        return context

    def form_valid(self, form):
        form.instance.product = Product.objects.get(pk=self.kwargs['pk'])
        return super().form_valid(form)

    def get_success_url(self):
        return reverse('dashboard:product-detail', kwargs={'pk': self.kwargs['pk']})


class ProductPhotoDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
    model = ProductPhoto
    pk_url_kwarg = 'photo_pk'
    template_name = 'dashboard/prodphoto_confirm_delete.html'
    success_message = 'Photo deleted.'

    def get_success_url(self):
        return reverse('dashboard:product-detail', kwargs={'pk': self.kwargs['pk']})


class CustomerListView(LoginRequiredMixin, ListView):
    model = User
    template_name = 'dashboard/customer_list.html'

    def get_queryset(self):
        object_list = User.objects.filter(
            Exists(
                Order.objects.filter(customer=OuterRef('pk'))
            ) | Q(is_staff=False)
        ).prefetch_related(
            'orders'
        ).annotate(
            num_orders=Count('orders')
        )

        return object_list


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


class CustomerUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = User
    template_name = 'dashboard/customer_form.html'
    context_object_name = 'customer'
    success_message = 'Customer saved.'
    fields = (
        'first_name',
        'last_name',
        'email',
        'is_staff',
        'addresses',
        'default_shipping_address'
    )

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