from django.shortcuts import render

from rest_framework import viewsets as meviewsets
from rest_framework.views import APIView
from app.applicationlayer.management.changerequest import serializers
from app.entities import models
from app.applicationlayer import paginators

from datetime import datetime
from datetime import timedelta

from rest_framework.response import Response
from rest_framework import status, views

from rest_framework.decorators import action
from django.http import Http404

from django.db.models import Q
import requests
from django.conf import settings
from rest_framework.exceptions import ValidationError
from django.db import transaction, IntegrityError, connection
from app.applicationlayer.utils import QuerySetHelper


class ChangeRequestTemplatesViewset(meviewsets.ModelViewSet):

    queryset = models.ChangeRequestTemplateHeader.objects.all()
    lookup_field = 'template_no'
    serializer_class = serializers.ChangeRequestTemplatesSerializer
    pagination_class = paginators.SimplePageNumberPagination

    def list(self, request, *args, **kwargs):
        
        self.queryset = self.queryset.filter(
            deleted_at=None
        )
        self.queryset = self.queryset.order_by('-created')
        
        return super(ChangeRequestTemplatesViewset, self).list(request)

    def retrieve(self, request, *args, **kwargs):
        instance = self.queryset.filter(
            deleted_at=None,
            template_no=str(self.kwargs.get('template_no'))
        ).first()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    def destroy(self, request, *args, **kwargs):
        try:
            # instance = self.get_object()
            template_no = self.kwargs['template_no']
            instance = models.ChangeRequestTemplateHeader.objects.filter(
                Q(template_no=template_no) &
                Q(deleted_at=None)
            ).update(deleted_at=datetime.utcnow())
            return Response({"message": "Deleted"}, status=status.HTTP_200_OK)
        except Exception as e:
            return Response(e,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def partial_update(self, request, *args, **kwargs):
        try:
            kwargs['partial'] = True
            # instance = self.get_object()
            template_no = self.kwargs['template_no']
            instance = models.ChangeRequestTemplateHeader.objects.filter(
                template_no=template_no
            ).order_by('-deleted_at')
            instance.update(deleted_at=None)
            message = "Archived Change Request restored"
            return Response(message, status=status.HTTP_200_OK)

        except Exception as e:
            message = {
                            500, 'failed',
                            'Request was not able to process' + str(e), []
                      }
            return Response(message, 
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    # @transaction.atomic
    # def create(self, request, *args, **kwargs):
    #     serializer = self.get_serializer(data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #     if not template_no.lower() == 'tmp':
    #         print('not tmp')
    #         form = request.data['template_no']
    #         prefix = request.data['requested_to_template_id']
    #         instance = models.ChangeRequestTemplateHeader.objects.filter(
    #             Q(requested_to_template_id=prefix) &
    #             Q(deleted_at=None)
    #         ).first()
            
    #         if instance and instance.template_no != request.data['template_no']:
    #             return Response(
    #                 {'message': "CR number prefix already exist"},
    #                 status=status.HTTP_400_BAD_REQUEST
    #             )
    #         else:
    #             models.ChangeRequestTemplateHeader.objects.filter(
    #                 template_no=template_no
    #             ).update(
    #                 deleted_at=datetime.now()
    #             )
    #             models.ChangeRequestTemplateStakeHolders.objects.filter(
    #                 template_no=template_no
    #             ).update(
    #                 deleted_at=datetime.now()
    #             )
    #             models.ChangeRequestTemplateAttachments.objects.filter(
    #                 template_no=template_no
    #             ).update(
    #                 deleted_at=datetime.now()
    #             )
    #             models.ChangeRequestTemplateDetails.objects.filter(
    #                 template_no=template_no
    #             ).update(
    #                 deleted_at=datetime.now()
    #             )
    #             models.ChangeRequestTemplateApprovers.objects.filter(
    #                 template_no=template_no
    #             ).update(
    #                 deleted_at=datetime.now()
    #             )
    #             series = template_no

    #     template_id = request.data['requested_to_template_id']
    #     check_prefix = models.ChangeRequestTemplateHeader.objects.filter(
    #         Q(requested_to_template_id=template_id) &
    #         Q(deleted_at=None)
    #     )
    #     if check_prefix.count() > 0 and template_no.lower() == 'tmp':
    #         return Response(
    #             {'message': "CR number prefix already exist"},
    #             status=status.HTTP_400_BAD_REQUEST
    #         )

    #     self.perform_create(serializer)

    #     if template_no.lower() == 'tmp':

    #         id = serializer.data['id']
    #         db_counter = models.ChangeRequestTemplateHeader.objects.filter(
    #             deleted_at=None
    #         ).count()
    #         db_counter = db_counter + 2
    #         db_counter = db_counter - 1

    #         models.ChangeRequestTemplateHeader.objects.filter(id=id).update(
    #             set__template_no=number_generator("TMP", db_counter)
    #         )
    #         series = number_generator("TMP", db_counter)

    #     headers = self.get_success_headers(serializer.data)
    #     return Response(
    #         data={"code": series},
    #         status=status.HTTP_201_CREATED, headers=headers
    #     )


class ChangeRequestTemplateApproversViewset(meviewsets.ModelViewSet):

    queryset = models.ChangeRequestTemplateApprovers.objects.all()
    serializer_class = serializers.ChangeRequestTemplateApproversSerializer
    pagination_class = paginators.SimplePageNumberPagination
    lookup_field = "code"

    def list(self, request, *args, **kwargs):
        self.queryset = self.queryset.filter(deleted_at=None)
        self.queryset = QuerySetHelper.Sort(self)
        
        return super(ChangeRequestTemplateApproversViewset, self).list(request)

    def retrieve(self, request, *args, **kwargs):
        instance = self.queryset.filter(deleted_at=None).first()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class ChangeRequestTemplateAttachmentsViewset(meviewsets.ModelViewSet):
    queryset = models.ChangeRequestTemplateAttachments.objects.all()
    serializer_class = serializers.ChangeRequestTemplateAttachmentsSerializer
    pagination_class = paginators.SimplePageNumberPagination
    lookup_field = "code"

    def list(self, request, *args, **kwargs):
        self.queryset = self.queryset.filter(deleted_at=None)
        self.queryset = QuerySetHelper.Sort(self)

        return super(
            ChangeRequestTemplateAttachmentsViewset, self
        ).list(request)


class ChangeRequestTemplateStakeHoldersViewset(meviewsets.ModelViewSet):

    queryset = models.ChangeRequestTemplateStakeHolders.objects.all()
    serializer_class = serializers.ChangeRequestTemplateStakeHoldersSerializer
    pagination_class = paginators.SimplePageNumberPagination

    def list(self, request, *args, **kwargs):
        self.queryset = self.queryset.filter(deleted_at=None)
        self.queryset = QuerySetHelper.Sort(self)
        # self.queryset = QuerySetHelper.Filter(self)
        return super(ChangeRequestTemplateStakeHoldersViewset, self).list(request)

    def retrieve(self, request, *args, **kwargs):
        instance = self.queryset.filter(deleted_at=None).first()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class ChangeRequestTemplateDetailsViewset(meviewsets.ModelViewSet):

    queryset = models.ChangeRequestTemplateDetails.objects.all()
    serializer_class = serializers.ChangeRequestTemplateDetailsSerializer
    pagination_class = paginators.SimplePageNumberPagination

    def list(self, request, *args, **kwargs):
        self.queryset = self.queryset.filter(deleted_at=None)
        self.queryset = QuerySetHelper.Sort(self)
        # self.queryset = QuerySetHelper.Filter(self)
        return super(ChangeRequestTemplateDetailsViewset, self).list(request)

    def retrieve(self, request, *args, **kwargs):
        instance = self.queryset.filter(deleted_at=None).first()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)
  

class ChangeRequestTemplatePost(APIView):

    @transaction.atomic()
    def post(self, request):
        template_header = request.data

        try:
            data_list_approver = []
            data_list_stake = []
            data_list_attach = []
            data_list_detail = []

            template_header_data = {
                'requested_to_template_name': template_header['requested_to_template_name'],
                'requested_to_template_id': template_header['requested_to_template_id'],
                'requested_to_objective': template_header['requested_to_objective'],
                'requested_to_target_date': template_header['requested_to_target_date'],
                'requested_to_priority': template_header['requested_to_priority'],
                'description': template_header['description'],
                'created_by_department': template_header['created_by_department'],
                'created_by_user': template_header['created_by_user'],
                'requested_to_company': template_header['requested_to_company'],
                'requested_to_department': template_header['requested_to_department'],
                'requested_to_user': template_header['requested_to_user']
            }

            tmp_approvers = template_header['tmp_approvers']
            tmp_stakes = template_header['tmp_stakes']
            tmp_attachments = template_header['tmp_attachments']
            tmp_details = template_header['tmp_details']

            sp1 = transaction.savepoint()  # nothing will save to db

            serializer = serializers.ChangeRequestTemplatesSerializer(
                data=template_header_data)
            
            if serializer.is_valid(raise_exception=True):
                serializer.save()
            
            tmp_id = serializer.data['template_no']

            # create template approvers

            for tmp_approver in tmp_approvers:
                tmp_approver['template_no'] = tmp_id
                data_list_approver.append(tmp_approver)

            serializerApprover = serializers.ChangeRequestTemplateApproversSerializer(
                data=data_list_approver, many=True)

            if serializerApprover.is_valid(raise_exception=True):
                serializerApprover.save()

            # create template stakes

            for tmp_stake in tmp_stakes:
                tmp_stake['template_no'] = tmp_id
                data_list_stake.append(tmp_stake)

            serializerStake = serializers.ChangeRequestTemplateStakeHoldersSerializer(
                data=data_list_stake, many=True)

            if serializerStake.is_valid(raise_exception=True):
                serializerStake.save()
            
            # create template attachments

            for tmp_attachment in tmp_attachments:
                tmp_attachment['template_no'] = tmp_id
                data_list_attach.append(tmp_attachment)

            serializerAttach = serializers.ChangeRequestTemplateAttachmentsSerializer(
                data=data_list_attach, many=True)

            if serializerAttach.is_valid(raise_exception=True):
                serializerAttach.save()

            # create template details
            
            for tmp_detail in tmp_details:
                tmp_detail['template_no'] = tmp_id
                data_list_detail.append(tmp_detail)

            serializerDetail = serializers.ChangeRequestTemplateDetailsSerializer(
                data=data_list_detail, many=True)
            
            if serializerDetail.is_valid(raise_exception=True):
                serializerDetail.save()

            message = {
                'code': 201,
                'status': 'success',
                'message': 'Template Details successfully saved!',
                'results': serializer.data
            }

            return Response(message, status=status.HTTP_201_CREATED)

        except ValidationError as e:
            transaction.savepoint_rollback(sp1)
            message = {
                'code': 400,
                'status': 'failed',
                'message': str(e),
            }
            return Response(message, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            transaction.savepoint_rollback(sp1)
            message = {
                'code': 500,
                'status': 'failed',
                'message': 'Request was not able to process' + str(e),
            }
            return Response(message,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class ChangeRequestFormsViewset(meviewsets.ModelViewSet):

    lookup_field = 'form_code'
    queryset = models.ChangeRequestFormHeader.objects.all()
    serializer_class = serializers.ChangeRequestFormHeaderSerializer
    pagination_class = paginators.SimplePageNumberPagination
    
    
    def list(self, request, *args, **kwargs):
        # id_number = logged_user(self)
        # id_number = 'Acct-20190813-0000138'
        
        # self.queryset = change_request.list_by_user(id_number)
        
        self.queryset = change_request.filter_base(
            self.queryset,
            request.query_params.get('company_requested_to'),
            request.query_params.get('department_requested_to'),
            request.query_params.get('date_modified_from'),
            request.query_params.get('date_modified_to'),
            request.query_params.get('date_required_from'),
            request.query_params.get('date_required_to'),
            request.query_params.get('form_type'),
        )

        if self.request.query_params.get('search'):
            search_key = self.request.query_params.get('search')
        
            self.queryset = self.queryset.filter(
                Q(requested_to_template_name__icontains=search_key.lower()) |
                Q(requested_to_template_id__icontains=search_key.lower())
            )
        
        # self.queryset = self.queryset.order_by('-created')
        self.queryset = QuerySetHelper.Sort(self)
        # self.queryset = QuerySetHelper.Search(self)  # comment

        return super(ChangeRequestFormsViewset, self).list(request)

    @action(detail=False,
            methods=['get'],
            url_path='dashboard',
            name="Dashboard Summary")
    def dashboard_view(self, request):

        id_number = logged_user(self)

        # id_number = 'Acct-20190813-0000138'
        
        self.queryset = change_request.list_by_user(id_number)

        self.queryset = change_request.filter_base(
            self.queryset,
            request.query_params.get('company_requested_to'),
            request.query_params.get('department_requested_to'),
            request.query_params.get('date_modified_from'),
            request.query_params.get('date_modified_to'),
            request.query_params.get('date_required_from'),
            request.query_params.get('date_required_to'),
            request.query_params.get('form_type'),
        )

        pending = self.queryset.filter(
            status__iexact='Pending'
        ).count()

        approved = self.queryset.filter(
            status__iexact='Approved'
        ).count()

        rejected = self.queryset.filter(
            status__iexact='Rejected'
        ).count()

        cancelled = self.queryset.filter(
            status__iexact='Cancelled'
        ).count()

        completed = self.queryset.filter(
            status__iexact='Closed'  #Completed
        ).count()

        high = self.queryset.filter(
            requested_to_priority='High'
        ).count()

        normal = self.queryset.filter(
            requested_to_priority='Normal'
        ).count()

        awaiting_filtered = change_request.filter_awaiting(self.queryset, id_number)

        # awaiting = awaiting_filtered.count()
        awaiting = 0

        for awaits in awaiting_filtered:

            if awaits.status.lower() == 'rejected':
                print("rejected")
            elif awaits.status.lower() == 'closed':
                print("closed")
            elif awaits.status.lower() == 'cancelled':
                print("cancelled")
            else:
                awaiting = awaiting + 1
        
        overdue_filtered = change_request.filter_overdue(self.queryset)

        overdue = overdue_filtered.count()
        
        message = {
            'account_no': id_number,
            'pending': pending,
            'approved': approved,
            'rejected': rejected,
            'cancelled': cancelled,
            'completed': completed,
            'high': high,
            'normal': normal,
            'awaiting': awaiting,
            'overdue': overdue,
            'code': 200,
            'status': 'success',
            'message': 'Dashboard Summary'
        }
       
        return Response(message, status=status.HTTP_200_OK)
        

    @action(detail=False,
            methods=['get'],
            url_path='status',
            name="Dashboard Summary Status")
    def list_by_status_view(self, request):

        id_number = logged_user(self)

        # id_number = 'Acct-20190531-0000002'

        self.queryset = change_request.list_by_user(id_number)

        self.queryset = change_request.filter_status(
            self.queryset,
            request.query_params.get('status')
        )

        self.queryset = change_request.filter_base(
            self.queryset,
            request.query_params.get('company_requested_to'),
            request.query_params.get('department_requested_to'),
            request.query_params.get('date_modified_from'),
            request.query_params.get('date_modified_to'),
            request.query_params.get('date_required_from'),
            request.query_params.get('date_required_to'),
            request.query_params.get('form_type'),
        )
        
        self.queryset = self.queryset.order_by('-created')
        self.queryset = QuerySetHelper.Sort(self)
        # self.queryset = QuerySetHelper.Filter(self)
        return super(ChangeRequestFormsViewset, self).list(request)
    
    
    @action(detail=False,
            methods=['get'],
            url_path='overdue',
            name="Dashboard Summary Overdue")
    def list_by_overdue_view(self, request):

        id_number = logged_user(self)

        # id_number = 'Acct-20190531-0000002'

        self.queryset = change_request.list_by_user(id_number)

        self.queryset = change_request.filter_overdue(self.queryset)

        self.queryset = change_request.filter_base(
            self.queryset,
            request.query_params.get('company_requested_to'),
            request.query_params.get('department_requested_to'),
            request.query_params.get('date_modified_from'),
            request.query_params.get('date_modified_to'),
            request.query_params.get('date_required_from'),
            request.query_params.get('date_required_to'),
            request.query_params.get('form_type'),
        )

        self.queryset = self.queryset.order_by('-created')
        self.queryset = QuerySetHelper.Sort(self)
        return super(ChangeRequestFormsViewset, self).list(request)


    @action(detail=False,
            methods=['get'],
            url_path='awaiting',
            name="Dashboard Summary Awaiting")
    def list_by_awaiting_view(self, request):

        id_number = logged_user(self)

        # id_number = 'Acct-20190813-0000137'

        self.queryset = change_request.list_by_user(id_number)

        self.queryset = change_request.filter_awaiting(self.queryset, id_number)

        self.queryset = change_request.filter_base(
            self.queryset,
            request.query_params.get('company_requested_to'),
            request.query_params.get('department_requested_to'),
            request.query_params.get('date_modified_from'),
            request.query_params.get('date_modified_to'),
            request.query_params.get('date_required_from'),
            request.query_params.get('date_required_to'),
            request.query_params.get('form_type'),
        )

        self.queryset = self.queryset.filter(status__ne='Rejected')

        self.queryset = self.queryset.filter(status__ne='Closed')

        self.queryset = self.queryset.filter(status__ne='Cancelled')

        self.queryset = self.queryset.order_by('-created')
        self.queryset = QuerySetHelper.Sort(self)
        return super(ChangeRequestFormsViewset, self).list(request)


    def destroy(self, request, *args, **kwargs):
        # instance = self.get_object()
        form_code = self.kwargs['form_code']
        instance = models.ChangeRequestFormHeader.objects.filter(
            form_code=form_code
        ).first()
        if instance.status.lower() == 'draft':
            models.ChangeRequestFormApprovers.objects(
                form_code=form_code
            ).delete()
            models.ChangeRequestFormDetails.objects(
                form_code=form_code
            ).delete()
            models.ChangeRequestFormStakeHolders.objects(
                form_code=form_code
            ).delete()
            models.ChangeRequestFormAttachments.objects(
                form_code=form_code
            ).delete()
            models.ChangeRequestFormTasks.objects(
                form_code=form_code
            ).delete()
            models.ChangeRequestFormHeader.objects(form_code=form_code).delete()
            # self.perform_destroy(instance)
            return Response({"message": "Change Request Deleted"}, status=status.HTTP_200_OK)
        else:
            message = {"message": "Cant delete this record, it has an ongoing tansaction"}
            return Response(
                message,
                status=status.HTTP_204_NO_CONTENT
            )

    def retrieve(self, request, *args, **kwargs):
        instance = self.queryset.filter(
            deleted_at=None,
            form_code=str(self.kwargs.get('form_code'))
        ).first()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    @action(detail=True,
        methods=['get'],
        url_path='history',
        name="CR History")
    def list_cr_history(self, request, form_code=None, **kwargs):
        
        form_code = self.kwargs['form_code']
        form_code_list = []
        form_code_list.append(form_code)

        for frmitem in models.ChangeRequestFormHeader.objects.filter(old_form_code__ne=None).order_by('created'):
            
            if frmitem.form_code == form_code:
                form_code_list.append(frmitem.old_form_code)
                form_code = frmitem.old_form_code

        # remove duplicates
        mylist = list(dict.fromkeys(form_code_list))
        print(mylist)

        queryset = models.ChangeRequestFormApprovers.objects.filter(
            (Q(action__ne=None) & Q(action__ne='')),
            form_code__in=mylist).order_by('created')

        self.serializer_class = serializers.ChangeRequestFormApproversSerializer

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)

            return self.get_paginated_response(serializer.data)




class ChangeRequestFormPost(APIView):

    # @transaction.atomic()
    def post(self, request):
        form_header = request.data

        try:
            data_list_approver = []
            data_list_stake = []
            data_list_attach = []
            data_list_detail = []

            form_header_data = {
                'requested_to_template_name': form_header['requested_to_template_name'],
                'requested_to_template_id': form_header['requested_to_template_id'],
                'requested_to_objective': form_header['requested_to_objective'],
                'requested_to_target_date': form_header['requested_to_target_date'],
                'requested_to_priority': form_header['requested_to_priority'],
                'description': form_header['description'],
                'status': form_header['status'],
                'company_desc': form_header['company_desc'],
                'department_desc': form_header['department_desc'],
                'requested_desc': form_header['requested_desc'],
                'old_form_code': form_header['old_form_code'],
                'requested_by_department': form_header['requested_by_department'],
                'requested_by_user': form_header['requested_by_user'],
                'requested_to_company': form_header['requested_to_company'],
                'requested_to_department': form_header['requested_to_department'],
                'requested_to_user': form_header['requested_to_user'],
                'template_no': form_header['template_no']
            }

            frm_approvers = form_header['frm_approvers']
            frm_stakes = form_header['frm_stakes']
            frm_attachments = form_header['frm_attachments']
            frm_details = form_header['frm_details']

            # sp1 = transaction.savepoint()  # nothing will save to db

            serializer = serializers.ChangeRequestFormHeaderSerializer(
                data=form_header_data)
            
            if serializer.is_valid(raise_exception=True):
                serializer.save()
            
            frm_id = serializer.data['form_code']
            print(frm_id)

            # create template approvers

            for frm_approver in frm_approvers:
                frm_approver['form_code'] = frm_id
                data_list_approver.append(frm_approver)

            serializerApprover = serializers.ChangeRequestFormApproversSerializer(
                data=data_list_approver, many=True)

            if serializerApprover.is_valid(raise_exception=True):
                serializerApprover.save()
            
            # create template stakes

            for frm_stake in frm_stakes:
                frm_stake['form_code'] = frm_id
                data_list_stake.append(frm_stake)

            serializerStake = serializers.ChangeRequestFormStakeHoldersSerializer(
                data=data_list_stake, many=True)

            if serializerStake.is_valid(raise_exception=True):
                serializerStake.save()
            
            # create template attachments

            for frm_attachment in frm_attachments:
                frm_attachment['form_code'] = frm_id
                data_list_attach.append(frm_attachment)

            serializerAttach = serializers.ChangeRequestFormAttachmentsSerializer(
                data=data_list_attach, many=True)

            if serializerAttach.is_valid(raise_exception=True):
                serializerAttach.save()

            # create template details
            
            for frm_detail in frm_details:
                frm_detail['form_code'] = frm_id
                data_list_detail.append(frm_detail)

            serializerDetail = serializers.ChangeRequestFormDetailsSerializer(
                data=data_list_detail, many=True)
            
            if serializerDetail.is_valid(raise_exception=True):
                serializerDetail.save()
            
            message = {
                'code': 201,
                'status': 'success',
                'message': 'Form Details successfully saved!',
                'results': serializer.data
            }

            return Response(message, status=status.HTTP_201_CREATED)

        except ValidationError as e:
            # transaction.savepoint_rollback(sp1)
            message = {
                'code': 400,
                'status': 'failed',
                'message': str(e),
            }
            return Response(message, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            # transaction.savepoint_rollback(sp1)
            message = {
                'code': 500,
                'status': 'failed',
                'message': 'Request was not able to process' + str(e),
            }
            return Response(message,
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)