from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.template.defaultfilters import slugify
from django.contrib.auth.decorators import permission_required
from django.views.decorators.csrf import csrf_exempt

from django.core.files.storage import default_storage

from modules.core.functions import *
from modules.core.decorators import *

#Forms
from forms import *

#Models
from models import *
from modules.payments.models import Payment
from modules.members.models import *
from modules.blocks.models import ContentBlock

from datetime import datetime

from emails import *

@members_only
def exam_application(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)

    try:
        exam_application = ExamApplication.objects.get(member=member,exam=exam_form)
    except ExamApplication.DoesNotExist:
        exam_application = False

    return render(request,'public/exam_application/application.html',{'exam_form':exam_form,'exam_application':exam_application})


@members_only
def start_application(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)

    try:
        exam_application = ExamApplication.objects.get(member=member,exam=exam_form)
        if exam_application.complete:
            messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        else:
            messages.error(request,'You have an application in progress, you can resume this using the button below.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))
    except ExamApplication.DoesNotExist:
        exam_application = ExamApplication(member=member,exam=exam_form)
        exam_application.save()

    return HttpResponseRedirect(reverse('exam_application_applicant',args=[exam_form.slug]))

@members_only
def restart_application(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)

    try:
        exam_application = ExamApplication.objects.get(member=member,exam=exam_form)
        if exam_application.complete:
            messages.error(request,'Sorry, you cannot restart an already complete application')
        else:
            exam_application.delete()
            exam_application = ExamApplication(member=member,exam=exam_form)
            exam_application.save()
            messages.success(request,'Application has been Restarted.')
    except ExamApplication.DoesNotExist:
        exam_application = ExamApplication(member=member,exam=exam_form)
        exam_application.save()

    return HttpResponseRedirect(reverse('exam_application_applicant',args=[exam_form.slug]))

@members_only
def applicant_details(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    applicant_details_form = ApplicantDetailsForm(instance=exam_application)

    if request.POST:
        applicant_details_form = ApplicantDetailsForm(request.POST,instance=exam_application)

        if applicant_details_form.is_valid():

            try:
                applicant_details_form.save()
                messages.success(request,'Information Saved')
                exam_application.status = 2
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_academic',args=[exam_form.slug]))
            except:
                pass

    return render(request,'public/exam_application/applicant-details.html',{'exam_form':exam_form,'exam_application':exam_application,'applicant_details_form':applicant_details_form})

@members_only
def academic_details(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    academic_details_form = AcademicDetailsForm(instance=exam_application)
    non_degree_evidence_form = NonDegreeEvidenceForm(instance=exam_application)

    if request.POST:
        academic_details_form = AcademicDetailsForm(request.POST,request.FILES,instance=exam_application)
        non_degree_evidence_form = NonDegreeEvidenceForm(request.POST,request.FILES,instance=exam_application)

        if request.POST.get('non_degree_applicant'):

            if non_degree_evidence_form.is_valid():
                non_degree_evidence_form.save()
                messages.success(request,'Information Saved')
                exam_application.status = 3
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_theory',args=[exam_form.slug]))

        else:
            if academic_details_form.is_valid():

                #try:
                academic_details_form.save()
                messages.success(request,'Information Saved')
                exam_application.status = 3
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_theory',args=[exam_form.slug]))
                #except:
                #    pass
            else:
                messages.error(request,'Form is not valid')



    return render(request,'public/exam_application/academic-details.html',{'exam_form':exam_form,'exam_application':exam_application,'academic_details_form':academic_details_form,'non_degree_evidence_form':non_degree_evidence_form})

@members_only
def theory_exams(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    year = exam_form.start_year
    years = []
    for i in range(0,6):
        years.append(year)
        year = year - 1

    theory_form = TheoryForm(instance=exam_application)
    exam_results_form = TheoryResultsLetterForm(instance=exam_application)

    if request.POST:

        theory_form = TheoryForm(request.POST,instance=exam_application)
        exam_results_form = TheoryResultsLetterForm(request.POST,request.FILES, instance=exam_application)

        if theory_form.is_valid():

            try:
                theory_form.save()
                exam_results_form.save()
                messages.success(request,'Information Saved')
                if exam_form.type == 're-validation':
                    exam_application.status = 6
                    exam_application.save()
                    return HttpResponseRedirect(reverse('exam_application_examiner',args=[exam_form.slug]))
                else:
                    exam_application.status = 4
                    exam_application.save()
                    return HttpResponseRedirect(reverse('exam_application_modalities',args=[exam_form.slug]))
            except:
                pass

    return render(request,'public/exam_application/theory-exams.html',{'exam_form':exam_form,'exam_application':exam_application,'years':years,'exam_results_form':exam_results_form})


@members_only
def modalities(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    modality_categories = ModalityCategory.objects.filter(exam_form=exam_form)

    if request.POST:
        application_modality_categories = ExamApplicationModalityCategory.objects.filter(exam_application=exam_application)
        application_modality_categories.delete()
        application_modality_items = ExamApplicationModalityItem.objects.filter(exam_application=exam_application)
        application_modality_items.delete()

        errors = False

        for category in modality_categories:
            application_modality_category = ExamApplicationModalityCategory(exam_application=exam_application,modality_category=category)
            application_modality_category.save()
            if request.POST.get('category_%s' % (category.id)):
                try:
                    category_scans = int(request.POST['category_%s' % (category.id)])
                    application_modality_category.total_scans = category_scans
                    application_modality_category.save()

                    if category_scans < category.minimum_scans:
                        messages.error(request, 'You have not entered enough Scans for <strong>%s</strong>' % (category))
                        errors = True

                except:
                    messages.error(request,'Please ensure the Scan Number is correct for <strong>%s</strong>' % (category))
                    errors = True
            else:
                messages.error(request, 'You have not entered Scans for <strong>%s</strong>' % (category))
                errors = True

            if not category.upload_disabled:
                if request.FILES.get('file_%s' % (category.id)) or request.POST.get('hidden_file_%s' % (category.id)):
                    if request.FILES.get('file_%s' % (category.id)):
                        name, ext = os.path.splitext('%s' % (request.FILES['file_%s' %  (category.id)]))
                        filename = 'scans_%s%s' % (application_modality_category.id, ext)
                        file_upload = handle_uploaded_file(request.FILES['file_%s' %  (category.id)], filename , private=True)
                        if filename:
                            application_modality_category.scans_file = 'exam_applications/%s' % (filename)
                            application_modality_category.save()
                        else:
                            messages.error(request, 'Sorry, could not upload your Scans for <strong>%s</strong>' % (category))
                            errors = True
                    else:
                        application_modality_category.scans_file = request.POST['hidden_file_%s' % (category.id)]
                        application_modality_category.save()
                else:
                    messages.error(request, 'You have not uploaded your Scans for <strong>%s</strong>' % (category))
                    errors = True

            if request.POST.get('training_began_%s' % (category.id)):
                training_began = request.POST['training_began_%s' % (category.id)]
                try:
                    training_began_date = datetime.strptime(training_began, "%m/%Y")
                    application_modality_category.training_began = training_began_date
                    application_modality_category.save()
                except Exception as e:
                    messages.error(request, 'Please ensure the date is correct for <strong>%s</strong>' % (category))
                    errors = True
            else:
                messages.error(request, 'You have not entered the Date your Training Began for <strong>%s</strong>' % (category))
                errors = True

            for item in category.get_items():
                if item.type == 'compulsory':
                    if not request.POST.get('scans_%s' % (item.id)):
                        messages.error(request,'Please tick to confirm you have completed the required number of scans for <strong>%s</strong>' % (item))
                        errors = True

                if request.POST.get('scans_%s' % (item.id)):
                    complete = True
                else:
                    complete = False

                application_modality_item = ExamApplicationModalityItem(exam_application=exam_application,modality_item=item,complete=complete)
                application_modality_item.save()

        if not errors:
            messages.success(request,'Information Saved')
            exam_application.status = 5
            exam_application.save()
            return HttpResponseRedirect(reverse('exam_application_experience',args=[exam_form.slug]))

    return render(request,'public/exam_application/modalities.html',{'exam_form':exam_form,'exam_application':exam_application,'modality_categories':modality_categories})


@members_only
def experience(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    experience_form = ExperienceForm(instance=exam_application)

    if request.method == 'POST':
        experience_form = ExperienceForm(request.POST,instance=exam_application)

        if experience_form.is_valid():

            try:
                experience_form.save()
                messages.success(request,'Information Saved')
                exam_application.status = 6
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_examiner',args=[exam_form.slug]))
            except:
                pass

        else:
            messages.error(request,'Please ensure you click the box to confirm your experience.')

    return render(request,'public/exam_application/experience.html',{'exam_form':exam_form,'exam_application':exam_application,'experience_form':experience_form})


@members_only
def examiner(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    examiner_form = ExaminerForm(instance=exam_application)

    if request.POST:
        examiner_form = ExaminerForm(request.POST,instance=exam_application)

        if examiner_form.is_valid():

            try:
                examiner_form.save()
                messages.success(request,'Information Saved')
                exam_application.status = 7
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_references',args=[exam_form.slug]))
            except:
                pass

    return render(request,'public/exam_application/examiner.html',{'exam_form':exam_form,'exam_application':exam_application,'examiner_form':examiner_form})


@members_only
def references(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    reference_forms = []

    """if exam_application.get_references():
        order = 1
        for reference in exam_application.get_references():
            reference_form = ReferenceForm(instance=reference,prefix='reference_%s' % (order))
            reference_forms.append(reference_form)
            order = order + 1
    else:
        reference_forms.append(ReferenceForm(prefix='reference_1'))"""
    reference_upload_form = ReferenceUploadForm(instance=exam_application)

    if request.POST or request.FILES:
        #find reference forms and process accordingly.
        reference_upload_form = ReferenceUploadForm(request.POST, request.FILES, instance=exam_application)

        print(reference_upload_form)
        print(request.FILES)

        if reference_upload_form.is_valid():

            reference_upload_form.save()

            messages.success(request, 'Information Saved')
            exam_application.status = 8
            exam_application.save()
            return HttpResponseRedirect(reverse('exam_application_declaration',args=[exam_form.slug]))

        """if request.POST.get('references'):
            reference_forms = []
            references = request.POST.getlist('references')
            errors = False

            for reference in references:
                reference_form = ReferenceForm(request.POST,prefix='reference_%s' % (reference))
                reference_forms.append(reference_form)
                if not reference_form.is_valid():
                    errors = True


            if not errors:
                for reference in exam_application.get_references():
                    reference.delete()

                order = 1
                for reference_form in reference_forms:
                    application_reference = reference_form.save(commit=False)
                    application_reference.exam_application = exam_application
                    application_reference.type = 'Line Manager'
                    application_reference.order = order
                    application_reference.save()
                    order = order + 1

                messages.success(request,'Information Saved')
                exam_application.status = 8
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_declaration',args=[exam_form.slug]))
            else:
                messages.error(request,'Please ensure you enter all fields correctly in order to continue')"""

    return render(request, 'public/exam_application/references.html', {'exam_form': exam_form, 'exam_application': exam_application, 'reference_upload_form': reference_upload_form})

@members_only
def declaration(request, form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication, member=member, exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    declaration_form = DeclarationForm(instance=exam_application)

    if request.POST:
        declaration_form = DeclarationForm(request.POST,instance=exam_application)

        if declaration_form.is_valid():
            #try:
            declaration_form.save()

            if exam_form.payment_amount:
                messages.success(request,'Information Saved')
                exam_application.status = 9
                exam_application.save()
                return HttpResponseRedirect(reverse('exam_application_payment',args=[exam_form.slug]))
            else:
                exam_application.complete = True
                exam_application.paid = True
                exam_application.save()

                #email
                application_form_completed(request,exam_application)

                #notification
                activity = UserActivity(member=member,type='exam-notification',title='Exam Application Completed',text='You have completed an exam application for <strong>%s</strong>, to view this submission please go <a href="%s">here</a>.' % (exam_form,reverse('account_view_exam_application',args=[exam_application.id])))
                activity.save()

                return HttpResponseRedirect(reverse('exam_application_complete',args=[exam_form.slug]))
            #except:
            #    pass

    return render(request,'public/exam_application/declaration.html',{'exam_form':exam_form,'exam_application':exam_application,'declaration_form':declaration_form})


@members_only
def payment(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)
    if exam_application.complete:
        messages.error(request,'Sorry, you have already made an application, you can review this application in your locker.')
        return HttpResponseRedirect(reverse('exam_application',args=[exam_form.slug]))

    if not exam_form.payment_amount:
        messages.warning(request,'There is no payment required for this Exam')
        return HttpResponseRedirect(reverse('exam_application_declaration',args=[exam_form.slug]))

    payment = Payment(member=member,type='exam_application',exam_application=exam_application)
    payment.save()

    if settings.DEVELOPMENT:
        payment.invoice = "Exam_Application_Payment_%sD" % (payment.id)
    else :
        payment.invoice = "Exam_Application_Payment_%s" % (payment.id)

    payment.save()

    secret_key = settings.WORLD_PAY_SECRET_KEY
    installation_id = settings.WORLD_PAY_INSTALLATION_ID
    redirect_url = "%s%s" % (settings.PAYMENT_URL,reverse('exam_application_payment_process',args=[exam_form.slug]))
    string = "%s:%s:%s:GBP:%s:%s" % (settings.WORLD_PAY_SECRET_KEY,settings.WORLD_PAY_INSTALLATION_ID,exam_form.payment_amount,payment.invoice,redirect_url)
    import hashlib
    encrypted_string = hashlib.md5(string).hexdigest()

    if request.POST:
        #process other payments
        if request.POST.get('payment_method'):
            payment_method = request.POST['payment_method']
            exam_application.payment_type = payment_method
            exam_application.complete = True
            exam_application.completed_time = datetime.now()
            exam_application.save()

            #email to go here
            application_form_completed_unpaid(request,exam_application)
            #send email

            return HttpResponseRedirect(reverse('exam_application_complete',args=[exam_form.slug]))

    return render(request,'public/exam_application/payment.html',{'exam_form':exam_form,'exam_application':exam_application,'payment':payment,'redirect_url':redirect_url,'encrypted_string':encrypted_string})


@csrf_exempt
def payment_process(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)

    callbackPW                              = request.POST.get('callbackPW', '')
    transStatus                             = request.POST.get('transStatus', '')
    authAmount                              = request.POST.get('authAmount', '')
    cartId                                  = request.POST.get('cartId', '')

    payment = get_object_or_404(Payment,invoice=cartId)

    errors = []
    error = False

    if not callbackPW or not transStatus or not authAmount or not cartId:
        error = True
        errors.append('Missing a Required Variable')

    if callbackPW != settings.WORLD_PAY_PASSWORD:
        error = True
        errors.append('World Pay Password Incorrect')

    if not errors:
        if transStatus == 'Y':

            if payment.status == 'pending':

                payment.status = 'complete'
                payment.amount = authAmount
                payment.save()

                exam_application = payment.exam_application
                exam_application.paid = True
                exam_application.payment_type = 'credit_card'
                exam_application.complete = True
                exam_application.completed_time = datetime.now()
                exam_application.save()

                #email to go here
                application_form_completed(request,exam_application)

                #notification
                activity = UserActivity(member=exam_application.member,type='exam-notification',title='Exam Application Completed',text='You have completed an exam application for <strong>%s</strong>, to view this submission please go <a href="%s">here</a>.' % (exam_form,reverse('account_view_exam_application',args=[exam_application.id])))
                activity.save()

            next = "%s%s" % (settings.URL,reverse('exam_application_payment_complete',args=[exam_form.slug]))

        else:
            payment.status = 'rejected'
            payment.save()
            next = "%s%s" % (settings.URL,reverse('exam_application_payment_failure',args=[exam_form.slug]))
    else:
        payment.status = 'rejected'
        payment.save()
        next = "%s%s" % (settings.URL,reverse('exam_application_payment_failure',args=[exam_form.slug]))

    return render(request,'public/payment-redirect.html',{'next':next})

def payment_complete(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)

    try:
        content_block = get_object_or_404(ContentBlock,slug='exam_payment_complete')
    except:
        content_block = False

    return render(request,'public/exam_application/payment-complete.html',{'exam_form':exam_form,'content_block':content_block})

def payment_failure(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    messages.error(request,'Sorry, we could not take payment at this time, please try again below.')

    return HttpResponseRedirect(reverse('exam_application_payment',args=[exam_form.slug]))

@members_only
def complete(request,form_slug):

    exam_form = get_object_or_404(ExamForm,slug=form_slug)
    member = get_object_or_404(Member,user=request.user)
    exam_application = get_object_or_404(ExamApplication,member=member,exam=exam_form)

    try:
        content_block = get_object_or_404(ContentBlock,slug='exam_other_complete')
    except:
        content_block = False

    return render(request,'public/exam_application/complete.html',{'exam_form':exam_form,'exam_application':exam_application,'content_block':content_block})
