from django.shortcuts import render
from .models import *
from .serializers import *
from core.mixin import LoggingMixin
from rest_framework import viewsets
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework import status
from django.core.mail import send_mail
from django.conf import settings
import requests
import json
from django.utils.http import is_safe_url
import uuid
import http.client
from rest_framework.decorators import action
from django.shortcuts import get_object_or_404
from push_notifications.models import GCMDevice
from users.models import UserModel
from rest_framework.decorators import api_view, APIView
from rest_framework.decorators import api_view, permission_classes
from users.permissions import IsAuthenticated, AllowAny, IsManager, IsSuperAdmin, IsEmployee, IsCustomer


class PaystackPlanViewSet(LoggingMixin, viewsets.ModelViewSet):
    """
    API endpoint that exposes the playstack interface
    """
    queryset = PaystackPlan.objects.all()
    serializer_class = PaystackPlanSerializer
    filterset_fields = ('name', 'currency', 'code', 'invoice_limit',
                        'interval', 'fundSource_id')

    def create(self, request):
        """
        Create a new paystack plan
        """
        # Create a fund source with the plan id
        savingsPlan = get_object_or_404(SavingsPlan,
                                        pk=request.data['savingsPlanId'])
        fundSource = FundSource.objects.create(info="Paystack fund collection",
                                               plan=savingsPlan)

        plan_instance = PaystackPlan.objects.create(
            name=request.data['name'],
            interval=request.data['interval'],
            amount=request.data['amount'],
            invoice_limit=request.data['invoice_limit'])

        if not is_safe_url(settings.PAYSTACK_PLAN_URL,
                           allowed_hosts={'api.paystack.co'},
                           require_https=True):
            print("unsafe url")
            return

        r = requests.post(
            settings.PAYSTACK_PLAN_URL,
            data={
                'key': settings.PAYSTACK_PUBLIC_KEY,
                'name': request.data['name'],
                'interval': request.data['interval'],
                'amount': request.data['amount'],
                'invoice_limit': request.data['invoice_limit'],
                'send_sms': True,
                'send_invoices': True
            },
            timeout=3.05,
            headers={
                'Accept': 'application/json',
                #   'Authorization':
                #   settings.PAYSTACK_AUTHORIZATION_KEY
                # "Authorization: Bearer SECRET_KEY"
            }).json()
        returnData = json.loads(r['data'])
        print(r['data'])
        if r.status_code == 200:
            # update plan_instance with the returned code from the paystack api
            plan_instance.code = returnData['plan_code']
            plan_instance.currency = returnData['currency']
            plan_instance.receivedData = r['data']
            plan_instance.save()

            plan = PaystackPlanSerializer(intance=plan_instance)
            plan.is_valid(raise_exception=True)
            # save as history
            return Response({
                'status': 'plan created',
                'data': plan.data
            }, status.HTTP_200_OK)
        return Response({'status': 'Plan creation failed'}, r.status_code)

    @action(detail=False, methods=['post'])
    def initSubscription(self, request, pk=None):
        pk = request.data['paystack_pk']
        email = request.data['user_email']
        plan = get_object_or_404(PaystackPlan, pk=pk)
        reference = str(uuid.uuid1())
        r = requests.post(
            settings.PAYSTACK_SUBSCRIPTION_URL,
            data={
                'email': email,
                'reference': reference,
                'plan': plan.code
            },
            timeout=3,
            headers={
                'Accept': 'application/json',
                #   'Authorization':
                #   settings.PAYSTACK_AUTHORIZATION_KEY
            }).json()
        returnData = json.loads(r['data'])
        print(r['data'])
        subs = Subscription.objects.create(
            email=email,
            reference=reference,
            plan_code=plan.code,
            email_token=returnData['email_token'],
            subscription_code=returnData['subscription_code'],
            paystack_plan=plan)

        subs.sub_history.add(
            SubscriptionHistory.objects.create(data=r['data']))
        subs.save()

        # save data as subscription object
        return Response({"status": "subscription ok"}, status.HTTP_200_OK)

    @action(detail=True, methods=['GET'])
    def disableSubscription(self, request, pk=None):
        '''
            Specify the subscription pk
        '''
        sub = get_object_or_404(Subscription, pk=pk)
        r = requests.post(
            settings.PAYSTACK_DISABLE_SUBSCRIPTION_URL,
            data={
                'code': sub.subscription_code,
                'token': sub.email_token,
            },
            timeout=3,
            headers={
                'Accept': 'application/json',
                #   'Authorization':
                #   settings.PAYSTACK_AUTHORIZATION_KEY
            }).json()
        return r

    @action(detail=True, methods=['GET'])
    def enableSubscription(self, request, pk=None):
        '''
          Specify the subscription pk
        '''
        sub = get_object_or_404(Subscription, pk=pk)
        r = requests.post(
            settings.PAYSTACK_ENABLE_SUBSCRIPTION_URL,
            data={
                'code': sub.subscription_code,
                'token': sub.email_token,
            },
            timeout=3,
            headers={
                'Accept': 'application/json',
                #   'Authorization':
                #   settings.PAYSTACK_AUTHORIZATION_KEY
            }).json()
        return r

    @action(detail=True, methods=['post'])
    @permission_classes([AllowAny])
    def subscriptionHook(self, request, pk=None):
        '''
          Specify the subscription pk
        '''
        ref = request.data['data']['reference']
        sub = get_object_or_404(SubscriptionHistory, reference=ref)

        # save as history
        sub.sub_history.add(
            SubscriptionHistory.objects.create(data=str(request.data['data'])))
        sub.save()

    # Allow authenticated users  create
    def get_permissions(self):
        print(self.action)
        if self.action in [  'list']:
            print('Updating')
            # which is permissions.IsAdminUser
            permission_classes = [IsEmployee]
        elif self.action in [
                'create', 'update', 'partial_update', 'initSubscription',
                'disableSubscription', 'enableSubscription',
        ]:
            # which is permissions.IsAuthenticated
            print('Creating')
            permission_classes = [IsAuthenticated]
        elif self.action in ['destroy']:
            # which is permissions.IsAuthenticated
            print('Deleting')
            permission_classes = [IsManager]
        else:
            # which is permissions.AllowAny
            print('Fetching')
            permission_classes = [AllowAny]
        return [permission() for permission in permission_classes]


class SubscriptionViewSet(LoggingMixin, viewsets.ModelViewSet):
    """
    API endpoint that exposes the playstack subscription
    """
    queryset = Subscription.objects.all()
    serializer_class = SubscriptionSerializer
    filterset_fields = ("email", "reference", "plan_code", 'email_token',
                        'subscription_code')
    # Allow authenticated users  create
    def get_permissions(self):
        print(self.action)
        if self.action in ['create', 'update', 'partial_update', 'list']:
            print('Updating')
            # which is permissions.IsAdminUser
            permission_classes = [IsEmployee]
        elif self.action in []:
            # which is permissions.IsAuthenticated
            print('Creating')
            permission_classes = [IsAuthenticated]
        elif self.action in ['destroy']:
            # which is permissions.IsAuthenticated
            print('Deleting')
            permission_classes = [IsManager]
        else:
            # which is permissions.AllowAny
            print('Fetching')
            permission_classes = [AllowAny]
        return [permission() for permission in permission_classes]


class SubscriptionHistoryViewSet(LoggingMixin, viewsets.ModelViewSet):
    """
    API end-point that exposes the  subscription history
    """
    queryset = SubscriptionHistory.objects.all()
    serializer_class = SubscriptionHistorySerializer
    filterset_fields = ("subscription_id", 'dateReceived')
    # Allow authenticated users  create
    def get_permissions(self):
        print(self.action)
        if self.action in ['update', 'list']:
            print('Updating')
            # which is permissions.IsAdminUser
            permission_classes = [IsEmployee]
        elif self.action in [ 'partial_update']:
            # which is permissions.IsAuthenticated
            print('Creating')
            permission_classes = [IsAuthenticated]
        elif self.action in ['destroy']:
            # which is permissions.IsAuthenticated
            print('Deleting')
            permission_classes = [IsManager]
        else:
            # which is permissions.AllowAny
            print('Fetching')
            permission_classes = [AllowAny]
        return [permission() for permission in permission_classes]

class TestimonialViewSet(LoggingMixin, viewsets.ModelViewSet):
    """
    API end-point that exposes the  Testimonial
    """
    queryset = Testimonial.objects.all()
    serializer_class = TestimonialSerializer
    filterset_fields = ("email", 'photoUrl', 'content')
    # Allow authenticated users  create
    def get_permissions(self):
        print(self.action)
        if self.action in ['update', 'list']:
            print('Updating')
            # which is permissions.IsAdminUser
            permission_classes = [IsEmployee]
        elif self.action in [ 'partial_update']:
            # which is permissions.IsAuthenticated
            print('Creating')
            permission_classes = [IsAuthenticated]
        elif self.action in ['destroy']:
            # which is permissions.IsAuthenticated
            print('Deleting')
            permission_classes = [IsManager]
        else:
            # which is permissions.AllowAny
            print('Fetching')
            permission_classes = [AllowAny]
        return [permission() for permission in permission_classes]

class FAQViewSet(LoggingMixin, viewsets.ModelViewSet):
    """
    API end-point that exposes the  FAQ
    """
    queryset = FAQ.objects.all()
    serializer_class = FAQSerializer
    filterset_fields = ("question", 'answer')
    # Allow authenticated users  create
    def get_permissions(self):
        print(self.action)
        if self.action in ['update', 'list']:
            print('Updating')
            # which is permissions.IsAdminUser
            permission_classes = [IsEmployee]
        elif self.action in [ 'partial_update']:
            # which is permissions.IsAuthenticated
            print('Creating')
            permission_classes = [IsAuthenticated]
        elif self.action in ['destroy']:
            # which is permissions.IsAuthenticated
            print('Deleting')
            permission_classes = [IsManager]
        else:
            # which is permissions.AllowAny
            print('Fetching')
            permission_classes = [AllowAny]
        return [permission() for permission in permission_classes]


class Emailer(APIView):
    """
    API wrapper to send mail
    """
    permission_classes = [IsAuthenticated]

    def post(self, request, format=None):
        subject = request.data["subject"]
        message = request.data["message"]
        from_email = request.data["from_email"]
        recipient_list = request.data["to_emails"]
        html_message = request.data["html_message"]
        try:
            send_mail(subject,
                      message,
                      from_email,
                      recipient_list,
                      fail_silently=True,
                      html_message=html_message)
        except Exception as error:
            Response({"status": error},
                     status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response({"status": "Message sent"}, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def singlePush(request):
    userid = request.data['user_pk']
    content = request.data['message']['content']
    title = request.data['message']['title']
    bage = request.data['message']['bage']
    icon = request.data['message']['icon']
    device = GCMDevice.objects.get(user__pk=userid)
    if device is None:
        return Response({'status': 'No notifications sent'},
                        status.HTTP_404_NOT_FOUND)
    device.send_message(content,
                        extra={
                            "title": title,
                            "icon": icon,
                            "bage": bage
                        })
    return Response({'status': 'Message sent'}, status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def bulkPush(request):
    content = request.data['message']['content']
    title = request.data['message']['title']
    bage = request.data['message']['bage']
    icon = request.data['message']['icon']
    userIds = request.data['user_pks']
    devices = GCMDevice.objects.filter(user__pk__in=userIds)
    if devices is None:
        return Response({'status': 'No notifications sent'},
                        status.HTTP_404_NOT_FOUND)
    devices.send_message(content,
                         extra={
                             "title": title,
                             "icon": icon,
                             "bage": bage
                         })
    return Response({'status': 'Message sent'}, status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def allPush(request):
    devices = GCMDevice.objects.all()
    content = request.data['message']['content']
    title = request.data['message']['title']
    bage = request.data['message']['bage']
    icon = request.data['message']['icon']
    if devices is None:
        return Response({'status': 'No notifications sent'},
                        status.HTTP_404_NOT_FOUND)
    devices.send_message(content,
                         extra={
                             "title": title,
                             "icon": icon,
                             "bage": bage
                         })
    return Response({'status': 'Message sent'}, status.HTTP_200_OK)



# @api_view(['POST'])
# def initiatePaystack(postdata):
#     payload = postdata
#     conn = http.client.HTTPConnection("api,paystack,co")
#     headers = {
#         'Authorization': "Bearer sk_test_a0d0acba6cec362f3db8bac0985e37ba2a482e8d",
#         'Content-Type': "application/json",
#         'Cache-Control': "no-cache",
#     }
#     conn.request("POST", "transaction,initialize", payload, headers)
#     res = conn.getresponse()
#     data = res.read()
#     return Response({'status': 'hello boss'}, status.HTTP_200_OK)

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def addDevice(request):
    token = request.data['registration_id']
    cloud_message_type = request.data['message_type']
    userId = request.data['user_pk']
    user = get_object_or_404(UserModel, pk=userId)
    # Create a FCM device
    fcm_device = GCMDevice.objects.create(
        registration_id=token,
        cloud_message_type=cloud_message_type,
        user=user)
    if fcm_device is None:
        return Response({'status': 'Device not registered'}, status.HTTP_500_INTERNAL_SERVER_ERROR)
    return Response({'status': 'Device added'}, status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def removeDevice(request):
    userId = request.data['user_pk']
    device = GCMDevice.objects.get(user__pk=userId)
    if device is None:
        return Response({'status': 'Not found'}, status.HTTP_404_NOT_FOUND)
    device.delete()
    return Response({'status': 'Device removed'}, status.HTTP_200_OK)