from typing import Any, Dict
from django.shortcuts import render, redirect
from django.views import View
from django.views.generic import TemplateView
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
from django.urls import reverse_lazy
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from .models import Product, Customer, Cart, OrderPlaced, WishList, User, Categories, SubCate
from .forms import CustomerRegistrationForm, CustomerProfileForm, ProductForm
from django.contrib import messages
from django.db.models import Q         
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.sessions.backends.db import SessionStore
import uuid

class Admin(View):
    def get(self, request, *args, **kwargs):
        customerCount = Customer.objects.all().count()
        productCount = Product.objects.all().count()
        orderCount = OrderPlaced.objects.all().count()
        orders = OrderPlaced.objects.all()
        return render(request, "app/admin.html", locals())

class adminCustomersView(ListView):
    model = Customer
    context_object_name = 'Customers'
    template_name = 'app/adminCustomers.html'
    

class adminProductView(ListView):
    model = Product
    context_object_name = 'products'
    template_name = 'app/adminProducts.html'
    
class adminAddProduct(CreateView):
    model = Product
    fields = '__all__'
    template_name = 'app/adminAddProduct.html'
    success_url = reverse_lazy('adminProductView')

class adminUpdateProduct(UpdateView):
    model = Product
    fields = '__all__'
    template_name = 'app/adminUpdateProduct.html'
    success_url = reverse_lazy('adminProductView')
    
class adminDeleteProduct(DeleteView):
    model = Product
    context_object_name = 'product'
    template_name = 'app/adminDeleteProduct.html'
    success_url = reverse_lazy('adminProductView')
    
class adminOrders(ListView):
    model = OrderPlaced
    context_object_name = 'Orders'
    template_name = 'app/adminOrders.html'
    

class adminOrderStatus(UpdateView):
    model = OrderPlaced
    fields = ['status']
    template_name = "app/adminOrderStatus.html"
    success_url = reverse_lazy('adminOrders')
    
    
class adminAddCategory(CreateView):
    model = Categories
    fields = '__all__'
    template_name = "app/adminAddCategory.html"
    success_url = reverse_lazy('admin-dashboard')

    def get_context_data(self, **kwargs):
        ctx = super(adminAddCategory, self).get_context_data(**kwargs)
        ctx['Categories'] = self.model.objects.all()
        return ctx
    
class adminAddSubCategory(View):
    def get(self, request, category):
        subCategories = SubCate.objects.filter(category__title=category)
        
        return render(request, "app/adminAddSubCategory.html", locals())
    def post(self, request, category):
        subCategories = SubCate.objects.filter(category__title=category)
        
        name = request.POST.get("name").replace(" ", "-")
        if name:
            name_list = [obj.name for obj in subCategories]
            
            if name in name_list:
                messages.warning(request, "This category is already Exited.")
            else:    
                category = Categories.objects.get(title=category)
                model = SubCate(name=name, category=category)
                model.save()
        
        if " " in name:
            messages.warning(request, "Invalid Input Data Space are not allowed.")
        
        return render(request, "app/adminAddSubCategory.html", locals())


class adminUpdateSubCategory(UpdateView):
    model = SubCate
    fields = ['name']
    template_name = "app/adminUpdateSubCategory.html"
    success_url = reverse_lazy('adminAddSubCategory')
    
def adminDeleteSubCategory(request,pk):
    cat = SubCate.objects.get(pk=pk)
    try:
        cat.delete()
    except:
        return HttpResponse('<h1>You can\'t delete this category.</h1>')
    return redirect("adminAddProduct/")


class adminUpdateCategory(UpdateView):
    model = Categories
    fields = '__all__'
    template_name = "app/adminUpdateCategory.html"
    success_url = reverse_lazy('adminOrders')


def adminDeleteCategory(request,pk):
    cat = Categories.objects.get(pk=pk)
    try:
        cat.delete()
    except:
        return HttpResponse('<h1>You can\'t delete this category.</h1>')
    return redirect("adminAddProduct/")


def home(request):
    if request.user.is_superuser:
        return redirect("admin-dashboard")
    data = Product.objects.all()
    return render(request, 'app/home.html', {"data":data})

class Category(View):
    def get(self, request, val):
        products = Product.objects.filter(categories__title=val)
        subCategories = SubCate.objects.filter(category__title=val)
        
        return render(request, 'app/category.html',locals())
    def post(self, request, val):
        selected_values  = request.POST.getlist('select')
        if selected_values:
            products = Product.objects.filter(categories__title=val).filter(subCate__name__in=selected_values)
        else:
            products = Product.objects.filter(categories__title=val)
        subCategories = SubCate.objects.filter(category__title=val)

        return render(request, 'app/category.html',locals())


class ProductDetail(View):
    
    def get(self, request, pk):
        product = Product.objects.get(id=pk)
        if request.user.is_authenticated:
            wishlist = WishList.objects.filter(Q(product=product) & Q(user=request.user))
        return render(request, 'app/productDetail.html',locals())

    def post(self, request, pk):

        product_id=request.POST.get('prod_id')  


        myProduct = Product.objects.get(id=product_id)
        product = Product.objects.get(id=pk)

        if request.user.is_authenticated:
            wishlist = WishList.objects.filter(Q(product=product) & Q(user=request.user))
        
        if not(Cart.objects.filter(Q(product_id=product_id) & Q(user_id = request.user.id))): #!  And check user
            try: 
                Cart(user=request.user, product=myProduct).save()
            except:
                cart_products = request.session.get('cart_products', {})
                
                if product_id not in cart_products:
                    cart_products[product_id] = 1
                    request.session['cart_products'] = cart_products
                      
        
        return render(request, 'app/productDetail.html',locals())


def SessionCartView(request):
    
    prodId = request.session.get('cart_products', {})

    products = []
    prodQ = []
    
    amount = 0

    for id, quantity in prodId.items():
        product = Product.objects.get(id=id)
        products.append(product)
        prodQ.append(quantity)
        amount += product.selling_price * quantity
        
    totalAmount = amount + 60

    zipped_data = zip(products, prodQ)
    data = Product.objects.all()
    return render(request, 'app/Cart.html',locals())

def increase_quantity(request, product_id):
    cart_products = request.session.get('cart_products', {})

    cart_products[product_id] += 1
    request.session['cart_products'] = cart_products

    return redirect('SessionCartView')

def decrease_quantity(request, product_id):
    cart_products = request.session.get('cart_products', {})
    
    if cart_products[product_id] > 1:
        cart_products[product_id] -= 1
        request.session['cart_products'] = cart_products

    return redirect('SessionCartView')

def remove_product(request, product_id):
    cart_products = request.session.get('cart_products', {})

    del cart_products[product_id]
    request.session['cart_products'] = cart_products


    return redirect('SessionCartView')

@method_decorator(login_required, name='dispatch')
class SessionCheckout(View):
    def get(self, request):
        #todo Clear the session
        cart_products = request.session.get('cart_products', {})
        
        if cart_products:
            for product_id, quantity in cart_products.items():

                myProduct = Product.objects.get(id=product_id)
                try:
                    Cart.objects.get(Q(product=myProduct) & Q(user=request.user))
                except:
                    cart = Cart(user = request.user, product = myProduct, quantity = quantity)
                    cart.save()
        
            #! Clear Session
            del request.session['cart_products']
            
        else:print("Not Working")

        return redirect("check")


@method_decorator(login_required, name='dispatch')
class Checkout(View):
    def get(self, request):
        cart_products = request.session.get('cart_products', {})
        
        Address = Customer.objects.filter(user=request.user)
        
        if not Customer.objects.filter(user=request.user).values():
            return redirect("profile")    

        cart_items = Cart.objects.filter(user=request.user)
        amount = 0
        
        for product in cart_items:
            values = product.quantity * product.product.selling_price
            amount += values
        totalAmount = amount + 60
        return render(request, "app/checkout.html", locals())
    
    def post(self, request):
        cart_items = Cart.objects.filter(user=request.user)
        customer = Customer.objects.filter(user=request.user).first()
        amount = 0
        for product in cart_items:
            values = product.quantity * product.product.selling_price
            orders = OrderPlaced(user=request.user, customer=customer, product = product.product, quantity=product.quantity, payment="Cash On Delivery",amount=values)
            orders.save()
            product.delete()

            amount += values
        totalAmount = amount

        return redirect("orders")

  
  
 
@login_required
def addToCart(request):
    user = request.user
    product_id=request.POST.get('prod_id')  
    myProduct = Product.objects.get(id=product_id)

    if not Cart.objects.filter(product=myProduct).exists():
        Cart(user=user,product=myProduct).save()
        return redirect("/cart")
    return redirect("/cart")



@login_required
def AuthCart(request):
    prod = request.session.get('cart_products', {})

    user= request.user
    cart  =Cart.objects.filter(user=user)
    amount = 0
    
    for p in cart:
        value = p.quantity * p.product.selling_price
        amount = amount + value
    totalAmount = amount + 60
    return render(request, 'app/addToCart.html',locals())

@login_required
def PlusCart(request):
    if request.method == "GET":
        prod_id = request.GET['prod_id']
        cartModel = Cart.objects.get(Q(product=prod_id) & Q(user=request.user))
        cartModel.quantity+=1
        cartModel.save()
        cart = Cart.objects.filter(user=request.user)
        amount = 0
        for product in cart:
            value = product.quantity * product.product.selling_price
            amount += value
        total = amount + 60
        Data = {
            'quantity' : cartModel.quantity,
            'amount':amount,
            "total":total,
        } 
        return JsonResponse(Data)
    
@login_required   
def MinusCart(request):
    if request.method == "GET":
        prod_id = request.GET['prod_id']
        cartModel = Cart.objects.get(Q(product=prod_id) & Q(user=request.user))
        cartModel.quantity-=1
        cartModel.save()
        cart = Cart.objects.filter(user=request.user)
        amount = 0
        for product in cart:
            value = product.quantity * product.product.selling_price
            amount += value
        total = amount + 60
        Data = {
            'quantity' : cartModel.quantity,
            'amount':amount,
            "total":total,
        } 
        return JsonResponse(Data)
    
@login_required
def RemoveCart(request):
    if request.method == "GET":
        prod_id = request.GET['prod_id']
        cartModel = Cart.objects.get(Q(product=prod_id) & Q(user=request.user))
        cartModel.delete()
        
        cart = Cart.objects.filter(user = request.user)
        amount = 0
        for product in cart:
            value = product.quantity * product.product.selling_price
            amount += value
        total = amount + 60
        Data = {
            'amount':amount,
            "total":total,
        }
        return JsonResponse(Data)


class CustomerRegistrationView(View):
    def get(self, request):
        form = CustomerRegistrationForm()
        return render(request, 'app/CustomerRegistration.html',locals())
    def post(self, request):
        form = CustomerRegistrationForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request,"Customer Register Successfully")
            form = CustomerRegistrationForm()
            return redirect("login")
        else:
            messages.warning(request, "Invalid Input Data")
        return render(request, 'app/CustomerRegistration.html',locals())


@method_decorator(login_required, name='dispatch')
class ProfileView(View):
    def get(self, request):
        form = CustomerProfileForm()
        return render(request, 'app/profile.html',locals())
    def post(self, request):
        form = CustomerProfileForm(request.POST)
        if form.is_valid():
            user = request.user
            name= form.cleaned_data['name']
            locality= form.cleaned_data['locality']
            city= form.cleaned_data['city']
            mobile= form.cleaned_data['mobile']
            zipcode= form.cleaned_data['zipcode']
            state= form.cleaned_data['state'] 
            reg = Customer(user=user, name=name,locality = locality, city = city, mobile = mobile, zipcode = zipcode, state = state)
            reg.save()
            messages.success(request, "Congratulations Profile Save Successfully")
            form = CustomerProfileForm()
        else:
            messages.warning(request,'Invalid Input Data')
        return render(request, 'app/profile.html',locals())
    

@login_required
def address(request):
    add = Customer.objects.filter(user=request.user)
    return render(request, 'app/address.html',locals())


@method_decorator(login_required, name='dispatch')
class UpdateAddressView(View):
    def get(self, request, pk):
        add = Customer.objects.get(pk=pk) #! Get instance
        form = CustomerProfileForm(instance=add)
        return render(request, 'app/updateAddress.html',locals())
    
    def post(self, request, pk):
        form = CustomerProfileForm(request.POST)
        if form.is_valid():
            add = Customer.objects.get(pk=pk)
            add.name = form.cleaned_data['name']
            add.locality = form.cleaned_data['locality']
            add.city = form.cleaned_data['city']
            add.mobile = form.cleaned_data['mobile']
            add.zipcode = form.cleaned_data['zipcode']
            add.state = form.cleaned_data['state']
            add.save()
            messages.success(request, "Update Address Successfully")
        else:
            messages.warning(request,'Invalid Input Data')
        
        if request.user.is_superuser:
            return redirect('adminOrders')
            
        return redirect('address')
    
@login_required
def payment_view(request):
    return render(request, 'app/payment.html')


@login_required
def orders(request):
    order_placed = OrderPlaced.objects.filter(user=request.user)
    return render(request, 'app/orders.html', locals())

def search(request):
    query = request.GET['search']
    totalitem = 0
    wishitem   = 0
    if request.user.is_authenticated:
        totalitem = len(Cart.objects.filter(user=request.user))
        wishitem = len(WishList.objects.filter(user=request.user))

    product = Product.objects.filter(Q(title__contains=query))

    return render(request, 'app/search.html', locals())


class Wish(ListView):
    model = WishList
    template_name = "app/wish.html"
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['wishlist_list'] = context['object_list'].filter(user=self.request.user)
        return context

@login_required
def WishOrNot(request, product_id):
    wish = None
    try:
        wish = WishList.objects.get(Q(product_id=product_id) & Q(user=request.user))
    except:
        print('Product is not in wish list')
    
    if wish is None:
        wish = WishList(product_id=product_id, user=request.user)
        wish.save()
    else:
        wish.delete()
    return redirect('product-detail', product_id)