import requests
from requests.auth import HTTPBasicAuth
from datetime import datetime
from django.contrib import messages 
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, View
from .models import Item, OrderItem, Order, BillingAddress, CheckOutAddress, Payment
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from .forms import CheckoutForm
import requests
from requests.auth import HTTPBasicAuth
from datetime import datetime
import base64
from .paytm import generate_checksum, verify_checksum
from django.http import JsonResponse
from urllib.request import urlopen 
from .generateAccessToken import get_access_token
from .stkPush import initiate_stk_push
from .callback import process_stk_callback
import json 


class IndexView(ListView):
	model = Item
	paginate_by = 8
	template_name = "index.html"


class ItemDetailView(DetailView):
	model = Item
	template_name = "product.html"


class HealthBeautyView(ListView):
    model = Item
    paginate_by = 8
    template_name = "health_beauty.html"


class FashionView(ListView):
    model = Item
    paginate_by = 8
    template_name = "fashion.html"


class HomeOfficeFurnitureyView(ListView):
    model = Item
    paginate_by = 8
    template_name = "home_and_furniture.html"


class Gaming(ListView):
    model = Item
    paginate_by = 8
    template_name = "gaming.html"


class Electronics(ListView):
    model = Item
    paginate_by = 8
    template_name = "electronics.html"

class HomeAppliances(ListView):
    model = Item
    paginate_by = 8
    template_name = "home_appliances.html"


class CheckoutView(View):

    def get(self, *args, **kwargs):
        order = Order.objects.get(user=self.request.user, ordered = False)
        form = CheckoutForm(self.request.POST or None)
        print(self.request.POST)
        context = {
            'form': form,
            'object':order,
        }
        return render(self.request, 'checkout.html', context)
    
    def post(self, *args, **kwargs):
        form = CheckoutForm(self.request.POST or None)
        try:
            order = Order.objects.get(user=self.request.user, ordered = False)
            if form.is_valid():
                url = "https://uat.jengahq.io/transaction/v2/payments"                
                telephone_no         = form.cleaned_data.get("telephone_no")
                email_address        = form.cleaned_data.get("email_address")
                checkout_address  = CheckOutAddress(
                    user          = self.request.user,
                    telephone_no  = telephone_no,
                    email_address = email_address,
                    token = token,
                    )
                checkout_address.save()
                order.checkout_address = checkout_address
                order.save()
                url = "https://uat.jengahq.io/transaction/v2/payments"
                payload = {
                    "customer": {
                        "mobileNumber": str(telephone_no),
                        "countryCode": "KE"
                        },
                    "transaction": {
                    "amount": "105.00",
                    "description": "please work",
                    "type": "EazzyPayOnline",
                    "reference": "692194625798"
                        }
                    }
                headers = {
                    "Authorization": get_token(),
                    "Content-Type": "application/json",
                    "signature": get_signature()
                    }

                response = requests.request("POST", url, json=payload, headers=headers)
                print(response)
                return redirect('core:checkout')
            messages.warning(self.request, "Failed checkout")
            return redirect('core:checkout')           
        except ObjectDoesNotExist:
            messages.error(self.request, "You do not have an active order")
            return redirect("core:order-summary")
        



class OrderSummaryView(LoginRequiredMixin, View):
	def get(self, *args, **kwargs):

		try:
			order = Order.objects.get(user=self.request.user, ordered = False)
			context = {
				'object':order
			}
			return render(self.request, 'order_summary.html',  context)
		except ObjectDoesNotExist:
			messages.error(self.request, "You do not have an active order")
			return redirect("/")


class PaymentView(View):
    def get(self, *args, **kwargs):
        order = Order.objects.get(user=self.request.user, ordered = False)
        form = CheckoutForm(self.request.POST or None)
#        print(self.request.POST)
        context = {
            'form': form,
            'object':order,
        }
        return render(self.request, "payment.html", context)


    def post(self, *args, **kwargs):
        order = Order.objects.get(user=self.request.user, ordered = False)

        unformatted_time = datetime.now()
        formatted_time = unformatted_time.strftime("%Y%m%d%H%M%S")
        passKey ='bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919'
        
        data_to_encode = ("174379" + passKey + formatted_time)
        encoded_string = base64.b64encode(data_to_encode.encode())
        decoded_password = encoded_string.decode("utf-8")

        consumer_key = '4fensZoqyeV2FfBrtAPdb0GsjAUoYn3XZeFdinK1RRuzSnYO'
        consumer_secret = 'mh4engtGfZp3S2bBWmMI8OAZKxv0wAmFxnVukc2i8BhebpdHADOY3Ec3IimOqs62'
        api_url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"

        try:
            r = requests.get(api_URL, auth=HTTPBasicAuth(consumer_key, consumer_secret))
        except:
            r = requests.get(api_URL, auth=HTTPBasicAuth(consumer_key, consumer_secret), verify=False)

        json_response = (r.json())
        my_access_token = json_response["access_token"]

        access_token = my_access_token

        api_parameters_cubes = (
            ("token",  access_token ),

            )

        api_parameters = dict(api_parameters_cubes)
        context = {
                    'api_parameters' : api_parameters,                   
                   }
        return render(self.request, 'wishlist.html', context)        

        amount = order.get_total()
        form = CheckoutForm(self.request.POST or None)  

        if form.is_valid():
#            telephone_no = request.POST['telephone_no']
            access_token = my_access_token

            api_url = "https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest"
            headers = {'Content-Type':'application/json',"Authorization": 'Bearer' + access_token}
            request = {
                "BusinessShortCode": "174379",
                "Password": decoded_password,
                "Timestamp": formatted_time,
                "TransactionType": "CustomerBuyGoodsOnline",
                "Amount": 1 ,
                "PassKey":"bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919",
                "PartyA": "600991" ,
                "PartyB": "600000",
                "PhoneNumber": "254728680519",
                "CallBackURL": "https://ip_address:port/callback",
                "AccountReference": "Test ",
                "TransactionDesc": "Test "
                }
            
#            print(request)    
            response = requests.post(api_url, json = request, headers=headers)
            return redirect("core:process_stk_callback")


        def process_stk_callback(request):
            stk_callback_response = json.loads(request.body)
            log_file = "Mpesastkresponse.json"
            with open(log_file, "a") as log:
                json.dump(stk_callback_response, log)
    
            merchant_request_id = stk_callback_response['Body']['stkCallback']['MerchantRequestID']
            checkout_request_id = stk_callback_response['Body']['stkCallback']['CheckoutRequestID']
            result_code = stk_callback_response['Body']['stkCallback']['ResultCode']
            result_desc = stk_callback_response['Body']['stkCallback']['ResultDesc']
            amount = stk_callback_response['Body']['stkCallback']['CallbackMetadata']['Item'][0]['Value']
            transaction_id = stk_callback_response['Body']['stkCallback']['CallbackMetadata']['Item'][1]['Value']
            user_phone_number = stk_callback_response['Body']['stkCallback']['CallbackMetadata']['Item'][4]['Value']
    
 #   if result_code == 0:
      #  store the transaction details in the database
            print(response, 'herez')
            payment = Payment()
            payment.mpesa_charge_id = response['to_add']
            payment.user = self.request.user
            payment.amount = amount
            payment.save()

            order.ordered = True
            order.payment = payment       
            order.save() 

def payments(request):
    context = {'api_parameters': request.session['api_parameters']}
    
    return render(request, 'redirect.html', context)


@login_required
def add_to_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_item, created = OrderItem.objects.get_or_create(
        item=item,
        user=request.user,
        ordered=False
    )
    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        # check if the order item is in the order
        if order.items.filter(item__slug=item.slug).exists():
            order_item.quantity += 1
            order_item.save()
            messages.info(request, "This item quantity was updated.")
            return redirect("core:order-summary")
        else:
            messages.info(request, "This item was added to your cart.")
            order.items.add(order_item)            
            return redirect("core:order-summary")
    else:
        ordered_date = timezone.now()
        order = Order.objects.create(
            user=request.user, ordered_date=ordered_date)
        order.items.add(order_item)
        messages.info(request, "This item was added to your cart.")
        return redirect("core:order-summary")
	

@login_required
def remove_from_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_qs = Order.objects.filter(
        user=request.user,
        ordered=False
    )
    if order_qs.exists():
        order = order_qs[0]
        # check if the order item is in the order
        if order.items.filter(item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(
                item=item,
                user=request.user,
                ordered=False
            )[0]
            order.items.remove(order_item)
            order_item.delete()
            messages.info(request, "This item was removed from your cart.")
            return redirect("core:order-summary")
        else:
            messages.info(request, "This item was not in your cart")
            return redirect("core:product", slug=slug)
    else:
        messages.info(request, "You do not have an active order")
        return redirect("core:product", slug=slug)


@login_required
def remove_single_item_from_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_qs = Order.objects.filter(
        user=request.user,
        ordered=False
    )
    if order_qs.exists():
        order = order_qs[0]
        # check if the order item is in the order
        if order.items.filter(item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(
                item=item,
                user=request.user,
                ordered=False
            )[0]
            if order_item.quantity > 1:
                order_item.quantity -= 1
                order_item.save()
            else:
                order.items.remove(order_item)
            messages.info(request, "This item quantity was updated.")
            return redirect("core:order-summary")
        else:
            messages.info(request, "This item was not in your cart")
            return redirect("core:product", slug=slug)
    else:
        messages.info(request, "You do not have an active order")
        return redirect("core:product", slug=slug)

class ContactView(ListView):
    model = Item
    template_name = "contact.html"

def get_access_token(request):
    consumer_key = '4fensZoqyeV2FfBrtAPdb0GsjAUoYn3XZeFdinK1RRuzSnYO' 
    consumer_secret = 'mh4engtGfZp3S2bBWmMI8OAZKxv0wAmFxnVukc2i8BhebpdHADOY3Ec3IimOqs62'
    access_token_url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"
    headers = {'Content-Type': 'application/json'}
    auth = (consumer_key, consumer_secret)
    try:
        response = requests.get(access_token_url, headers = headers, auth = auth)
        response.raise_for_status()
        result = response.json()
        access_token = result['access_token']
        return JsonResponse({'access_token' :access_token})
    except requests.exceptions.RequestException as e:
        return JsonResponse({'error':str(e)})

def get_access_token(request):
    consumer_key = 'ovVH1R7FRfarkHwP7c7sta517O0KJfsk8TjsLtgv0sjwI0kt' 
    consumer_secret = 'zU6LTbXsjwqnaxG31bdEiw9FIFeyGHGZHg7m3D6CskMeYgNAuYxISsPs22Gt5o8x'
    api_URL = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"
    headers = {'Content-Type': 'application/json'}
    auth = (consumer_key, consumer_secret)
    try:
        r = requests.get(api_URL, auth=HTTPBasicAuth(consumer_key, consumer_secret))
        json_response = (r.json())
        my_access_token = json_response["access_token"]
        access_token = my_access_token
        return JsonResponse({'access_token' :access_token})
    except requests.exceptions.RequestException as e:
        return JsonResponse({'error':str(e)})


def request_appointment(request):    
    if request.method == 'POST':
        form = AppointmentForm(request.POST)
        if form.is_valid():
            access_token_response = get_access_token(request)
            if isinstance(access_token_response,JsonResponse):
                access_token = access_token_response.content.decode('utf-8')
                access_token_json = json.loads(access_token)
                access_token = access_token_json.get('access_token')
                if access_token:
                    amount = 1
                    phone = '254728680519'
                    passkey = 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919'
                    business_short_code = '174379'
                    process_request_url = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest'
                    callback_url = 'https://sibia.africa/callback'
                    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
                    password = base64.b64encode((business_short_code + passkey + timestamp).encode()).decode()
                    party_a = phone
                    party_b = '254728680519'
                    account_reference = 'SIBIA'
                    transaction_desc = 'stkpush test'
                    stk_push_headers = {
                        'Content-Type':'application/json',
                        "Authorization": 'Bearer ' + access_token
                    }
                    stk_push_payload = {
                        "BusinessShortCode": business_short_code,
                        "Password": password,
                        "Timestamp": timestamp,
                        "TransactionType": "CustomerPayBillOnline",
                        "Amount": amount ,                
                        "PartyA": phone,
                        "PartyB": business_short_code,
                        "PhoneNumber": party_a,
                        "CallBackURL": callback_url,
                        "AccountReference": account_reference,
                        "TransactionDesc": transaction_desc,
                    }                    

                    response = requests.post(process_request_url,headers=stk_push_headers,
                        json= stk_push_payload)
                    returned_xml = response.text
                    returned_json = {}
                    print(returned_xml)
                    print(json.dumps(returned_json, indent=2),'heree')
                else:
                    return JsonResponse({'error': 'STK push failed.'})
    return render(request, 'redirect.html', context) 
           
def get_access_token(request):
    consumer_key = 'ovVH1R7FRfarkHwP7c7sta517O0KJfsk8TjsLtgv0sjwI0kt' 
    consumer_secret = 'zU6LTbXsjwqnaxG31bdEiw9FIFeyGHGZHg7m3D6CskMeYgNAuYxISsPs22Gt5o8x'
    api_URL = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"
    headers = {'Content-Type': 'application/json'}
    auth = (consumer_key, consumer_secret)
    try:
        r = requests.get(api_URL, auth=HTTPBasicAuth(consumer_key, consumer_secret))
        json_response = (r.json())
        my_access_token = json_response["access_token"]
        access_token = my_access_token
        return JsonResponse({'access_token' :access_token})
    except requests.exceptions.RequestException as e:
        return JsonResponse({'error':str(e)})


def request_appointment(request):
    
    if request.method == 'POST':
        form = AppointmentForm(request.POST)
        if form.is_valid():
            access_token_response = get_access_token(request)
            if isinstance(access_token_response,JsonResponse):
                access_token = access_token_response.content.decode('utf-8')
                access_token_json = json.loads(access_token)
                access_token = access_token_json.get('access_token')
                if access_token:
                    amount = 1
                    phone = '254708374149'
                    passkey = 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919'
                    business_short_code = '174379'
                    process_request_url = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest'
                    callback_url = 'https://sibia.africa/callback'
                    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
                    password = base64.b64encode((business_short_code + passkey + timestamp).encode()).decode()
                    party_a = phone
                    party_b = '254708374149'
                    account_reference = 'SIBIA'
                    transaction_desc = 'stkpush test'
                    stk_push_headers = {
                        'Content-Type':'application/json',
                        "Authorization": 'Bearer ' + access_token
                    }
                    stk_push_payload = {
                        "BusinessShortCode": business_short_code,
                        "Password": password,
                        "Timestamp": timestamp,
                        "TransactionType": "CustomerPayBillOnline",
                        "Amount": amount ,                
                        "PartyA": phone,
                        "PartyB": business_short_code,
                        "PhoneNumber": party_a,
                        "CallBackURL": callback_url,
                        "AccountReference": account_reference,
                        "TransactionDesc": transaction_desc,
                    }

                    try:
                        response = requests.post(process_request_url,headers=stk_push_headers,json= stk_push_payload)
                        returned_xml = response.text
                        returned_json = {}
                        print(json.dumps(returned_json, indent=2),'heree')
                        checkout_request_id = returned_json['CheckoutRequestId']
                        response_code = returned_json["ResponseCode"]
                        if response_code == "0":
                            return JsonResponse({"CheckoutRequestId":checkout_request_id})
                        else:
                            return JsonResponse({'error': 'STK push failed.'})
                    except requests.exceptions.RequestException as e:
                        return JsonResponse({'error':str(e)})
                else:
                    return JsonResponse({"error":'failed to retrieve access_token'})

