from django.shortcuts import render
from django.http import HttpResponse
from django.core.paginator import Paginator
from django.http import HttpResponseRedirect
from django.db.models import Max
from django.shortcuts import redirect
from .forms import UploadFileForm
from . newQuiz import readCSV
from . models import Questions
from . models import quiz
from .models import submission
from .models import cribs
from .models import result as results
from .models import cribs as crib
from .models import Permission
from .models import log
import collections
from django.db import connection, transaction
import numpy as np
import math
import pandas as pd
import scipy.stats as stats
import csv
from prettytable import PrettyTable
#for login
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.db.models import Count
import matplotlib.pyplot as plt, mpld3
import json
import random
import string 
from datetime import datetime
from django.views.decorators.clickjacking import xframe_options_exempt
from django.core.files import File
from django.utils import timezone
from django.core.files.storage import default_storage

startedquiz = dict()

def index(request):
    """ This function is responsible for for rendering the quiz page to the student for the selected quiz by the student
    """
    quiz_id = int(request.GET['q'])
    quizInstance = quiz.objects.get(pk=quiz_id)
    obj = Questions.objects.filter(quizId=quizInstance).all().order_by('questionId')
    endtime = quizInstance.end_datetime
    endtime = json.dumps(endtime.isoformat())
    count = len(obj)
    return render(request,'index.html',{'questions':obj,'count':count, 'endtime': endtime, 'quizId': quiz_id})

@login_required
def result(request):
    """This function is called on submission of quiz to  calculate the marks og the student the marks are added to total score for
    every correct answer and for every wronf answer the negative marks set by instructor are deducted"""
    if request.user.is_authenticated and request.method =="POST":
        quizId=int(request.POST['quizId'])
        quizInstance = quiz.objects.get(pk=quizId)
        prev_subm = submission.objects.all().filter(quizId=quizInstance, studentId=request.user)
        score = 0
        if len(prev_subm)==0:
            for questionno in request.POST:
                if questionno.startswith('question_'):
                    questionId = int(questionno[9:])
                    questionInstance = Questions.objects.get(pk=questionId)
                    q=Questions.objects.all().filter(quizId=quizInstance,questionId=questionId).values()
                    if(request.POST[questionno]==q[0]['answer']):
                        score+=q[0]['marks']
                    else:
                        score-=q[0]['negative']
                    t=submission(questionId=questionInstance, option=request.POST[questionno], studentId=request.user, quizId=quizInstance)
                    t.save()
            t=results(quizId=quizInstance,studentId=request.user,marks=int(score))
            t.save()
            return redirect('/view_submission/?q='+str(quizId))
        else:
            return HttpResponse("You have already submitted this quiz")
                

    
    
def save_ans(request):
    """
    this function keeps saving the response of the quiz while the student is attempting in order to ensure if due to network failure 
    student quiz stops then he can continue later from the point where he was interrupted
    """
    ans = request.GET['ans']
    quizId=request.GET['quizId']
    questionId=request.GET['questionId']
    studentId=1# initialize here student id
    t=submission(questionId=questionId,option=ans,quizId=quizId,studentId=studentId)
    t.save()
    return HttpResponse('')

def save_cribs(request):
    """This function saves the cribs that the student has raised"""
    crib=request.GET.get('cribs')
    quizId=int(request.GET.get('quiz'))
    quizInstance = quiz.objects.get(pk=quizId)
    questionId=int(request.GET.get('question'))
    questionInstance = Questions.objects.get(pk=questionId)
    t=cribs(cribs=crib,studentId=request.user,questionId=questionInstance,quizId=quizInstance)
    t.save()
    return HttpResponse('Suuuuuccess')  
    
def upload(request):
    """This function Renders the upload page for instructor to upload quiz through csv"""
    return render(request,'upload.html')

@login_required
def student(request):
    """This function depending on the role of the logged in user load the professor dasboard or student dashboard"""
    role = Permission.objects.all().filter(userId=request.user).values('role')
    if role:
        role = role[0]['role']
        if role == "P":    
            return render(request,'professor.html')
        else:
            return HttpResponse('Role not configured for this user')
    else:
        return render(request,'student.html')

def ongoing_quiz(request):
    """Displays all ongoing quiz to the professor who has hosted the quiz"""
    quizzes = quiz.objects.all().order_by('-date', '-startTime')
    return render(request, 'ongoing_quiz.html', {'quizId': quizzes})

def upload_file(request):
    """ This function reads the csv file and inserts the questions into the database """
    uploaded=False
    temp1='test'
    random_code = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 6)) 
    q= quiz(length=request.POST.get('length'),quizCode=random_code,quizInfo=request.POST.get('quiz_name'),date=request.POST.get('date'),
    quizInstructor=request.user,startTime =request.POST.get('startTime'),quizDone=False)
    q.save()
    form = UploadFileForm(request.POST, request.FILES)
    if request.method == 'POST' and form.is_valid():
        handle_uploaded_file(request.FILES['file'],q)
        uploaded=True
        return HttpResponse('success')

    else :
        return render(request,'upload.html',{temp1:'invalid File'})
    
    
def instructor(request):
    """This function is used to display the instructor with graphs(bell curve and histogram) , cribs raised by the students of the quiz selected"""
    q_id = request.GET.get('quiz_id')
    quizId = 0
    allquizs = quiz.objects.all().filter(quizInstructor=request.user).order_by('-date', '-startTime')
    if q_id:
        quizId = int(q_id)
    else:
        #quizId = quiz.objects.all().filter(quizInstructor=request.user)[0]
        if True:
            quizId = allquizs[0].quizId
        else:
            print(quizId)

    quizInstance = quiz.objects.all().filter(quizId=quizId, quizInstructor=request.user)[0]
    students = results.objects.all().filter(quizId=quizId).values('studentId')
    marks = results.objects.all().filter(quizId=quizId).values('marks')
    cribs=crib.objects.all().filter(quizId=quizId).select_related()
   
    fig, ax = plt.subplots()
    allMarks=list()
    for mark in marks:
        allMarks.append(mark['marks'])
    allStudents=list()
    for student in students:
        allStudents.append(student['studentId'])
    std=np.std(allMarks)
    mean=np.mean(allMarks)
    data =allMarks
    c = collections.Counter(data)
    c = sorted(c.items())
    score_num = [i[0] for i in c]
    freq = [i[1] for i in c]
    plt.barh(score_num, freq)
    plt.title("Score V/S N.O of Students")
    plt.xlabel("N.O of Students")
    plt.ylabel("Scores")
    ax.set_xticks(range(1,len(allMarks)+1))
    #ax.set_xticklabels(months)
    html_graph = mpld3.fig_to_html(fig) 
    fig1, ax1 = plt.subplots()
    mu = mean
    variance = np.std(allMarks)
    sigma = math.sqrt(variance)
    x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
    ax1.plot(x, stats.norm.pdf(x, mu, sigma))
    ax1.set_title('Normal Distribution for Scores to Students')
    ax1.set_xlabel('Score')
    ax1.set_ylabel('PDF')
    html_graph1 = mpld3.fig_to_html(fig1)
    quizDone = False
    if quizInstance.end_datetime < datetime.now():
        quizDone = True
    return render(request, 'instructor.html',{"graph": html_graph, "graph1": html_graph, "graph2": html_graph1,'quiz':quizInstance,'cribs':cribs, 'all_quizes': allquizs, 'quizDone':quizDone})

def quizTable(request):
    """This function helps in rendering all the quiz hosted by the instructor"""
    quizs = quiz.objects.filter(quizInstructor=request.user).all()
    return render(request,'quizTable.html',{'quiz':quizs})

def handle_uploaded_file(f,q1):
    """This function reads the csv file uploaded by the instructor and makes insert into the database"""
    with open('name.csv', 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)
    destination=open("name.csv","r") 
    rows=readCSV(destination)
    for row in rows:
        
        q=Questions(question=row[0],option1=row[1],option2=row[2],option3=row[3],option4=row[4],answer=row[5],type=row[6],marks=int(row[7]),negative=float(row[8]),explainations=row[9],quizCode=q1.quizCode,quizId=q1)#hardcoded quizid
        q.save()

def create_quiz(request):
    return render(request, 'quiz_create.html')


#login functionality
def sign_up(request):
    """This function renders the sign up page for the users"""
    context = {}
    form = UserCreationForm(request.POST or None)
    if request.method == "POST":
        if form.is_valid():
            user = form.save()
            login(request,user)
            return render(request,'student.html')
    context['form']=form
    return render(request,'registration/signup.html',context)



@login_required
def submissions(request):
    """ This function helps in rendering the submission page showing the student all the previous attempted quizzes"""
    #prev_subm = submission.objects.all().filter(studentId=request.user)
    prev_subm = results.objects.all().filter(studentId=request.user).select_related().all()
    return render(request,'submissions.html', { 'submissions' : prev_subm })


@login_required
def view_sub(request):
    """This function gives details to the student about the completed quiz consisting of  correct answers 
    and choosen answers also the explainations for the questions provided by the professor"""
    if request.method == "GET":
        quizId = int(request.GET.get('q'))
        quizInstance = quiz.objects.get(pk=quizId)
        subs = submission.objects.filter(quizId=quizInstance, studentId=request.user).select_related().all()
        score = 0
        total = 0
        message = ''
        for sub in subs:
            if sub.option == sub.questionId.answer:
                score = score + sub.questionId.marks
            else:
                score = score - sub.questionId.negative
            total = total + sub.questionId.marks
        return render(request,'view_submissions.html', { 'submissions' : subs , 'score': round(score,2), 'total': total, 'quizId': quizId })
        

def add_quiz(request):
    """This function makes insert into database for all the manually entered quiz questions"""
    vals=list()
    for req in request.POST.values():
        vals.append(req)
    i=1
    quizName= vals[i]
    i+=1
    date=vals[i]
    i+=1
    startTime=vals[i]
    i+=1
    length=vals[i]
    i+=1
    random_code = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 6)) 
    q= quiz(length=length,quizCode=random_code,quizInfo=quizName,date=date,
    quizInstructor=request.user,startTime =startTime,quizDone=False)
    q.save()

    while(i<len(vals)):
        
        row=(vals[i],vals[i+1],vals[i+2],vals[i+3],vals[i+4],vals[i+5],vals[i+6],vals[i+7],vals[i+8])
        q1=Questions(question=row[0],option1=row[1],option2=row[2],option3=row[3],option4=row[4],
        answer=row[7],marks=int(row[5]),negative=float(row[6]),explainations=row[8],quizCode=q.quizCode,quizId=q)
        print(row)
        q1.save()
        i=i+9
    return render(request,'professor.html',{'quiz_upload':True})#(request,'success')

def monitor(request):
    """
    Thid function renders the monitor page for the instructor to view ongoing quiz , and monitor the student activity
    """
    q_id = request.GET.get('quiz')
    allquizs = quiz.objects.all().filter(quizInstructor=request.user).order_by('-date', '-startTime')

    if q_id:
        quizId = int(q_id)
        quizInstance = quiz.objects.get(pk=quizId)
        startedquiz[quizId] = dict()
        return render(request, 'monitor.html', { 'quiz': quizInstance , 'all': allquizs })
    else:
        quizId = allquizs[0].quizId
        startedquiz[quizId] = dict()
        return render(request, 'monitor.html', { 'quiz': allquizs[0] , 'all': allquizs })
    

@xframe_options_exempt
def getbeat(request):
    """This function track the student activity for displaying the same on the instructor monitor page"""
    quizId = int(request.GET.get('quiz'))
    test = startedquiz.get(quizId)
    return render(request,'student_activity.html', {'activity': test })

def view_logs(request):
    """THus function helps in viewing all the quizzes logs"""
    quizId = int(request.GET.get('quiz'))
    quizInstance = quiz.objects.get(pk=quizId)
    quiz_logs = log.objects.all().filter(quizId=quizInstance)
    return render(request,'log.html', {'logs': quiz_logs })

def heartbeat(request):
    """This function keeps track of student whether he exited full screen and which question he is currently on"""
    quizId = int(request.GET.get('quiz'))
    quizInstance = quiz.objects.get(pk=quizId)
    if quizId in startedquiz:
        question = int(request.GET.get('question'))
        fs = request.GET.get('fullscreen')
        db = request.GET.get('log')
        time = timezone.now()
        jtime = json.dumps(time.isoformat())
        startedquiz[quizId][request.user] = (question, fs, jtime)
        if db == "true":
            if fs == "true":
                fstext="Entered Fullscreen"
            else:
                fstext="Left Fullscreen"
            l=log(quizId=quizInstance, studentId=request.user, fullscreen=fstext, questions=str(question))
            l.save()
            print("Log saved!")
            
    return HttpResponse('')

