package com.infinite.focus.server.tests;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;

import com.cloudinary.Cloudinary;
import com.cloudinary.utils.ObjectUtils;
import com.infinite.focus.server.auth.AccountRepository;
import com.infinite.focus.server.auth.AvatarRepository;
import com.infinite.focus.server.auth.Instructor;
import com.infinite.focus.server.auth.InstructorRepository;
import com.infinite.focus.server.auth.Student;
import com.infinite.focus.server.auth.StudentRepository;
import com.infinite.focus.server.home.DailyAppreciationRepository;
import com.infinite.focus.server.home.MoodUpdateRepository;
import com.infinite.focus.server.home.QuoteRepository;
import com.infinite.focus.server.lessons.Lesson;
import com.infinite.focus.server.lessons.LessonRecord;
import com.infinite.focus.server.lessons.LessonRecordRepository;
import com.infinite.focus.server.lessons.LessonRepository;
import com.infinite.focus.server.lessons.LessonWrapper;
import com.infinite.focus.server.students.Class;
import com.infinite.focus.server.students.ClassRepository;
import com.infinite.focus.server.wall.WallPost;
import com.infinite.focus.server.wall.WallPostAttachment;
import com.infinite.focus.server.wall.WallPostAttachmentRepository;
import com.infinite.focus.server.wall.WallPostRepository;
import com.infinite.focus.server.wall.WallPostRequestRepository;
import com.infinite.focus.server.wall.WallPostWrapper;

/**
 * 
 * @author Saboor
 * 
 *
 */


@CrossOrigin(origins = "http://localhost:8383")
@RestController
@RequestMapping("api/test")

public class TestController {
	
	 	private AccountRepository accountRepository;
		private StudentRepository studentRepository;
		private InstructorRepository instructorRepository;
		private AvatarRepository avatarRepository;
	    private BCryptPasswordEncoder bCryptPasswordEncoder;
	    private WallPostRepository wallPostRepository;
	    private WallPostAttachmentRepository wallPostAttachmentRepository;
	    private WallPostRequestRepository wallPostRequestRepository;
	    private QuoteRepository qouteRepository;
	    private MoodUpdateRepository moodUpdateRepository;
	    private DailyAppreciationRepository dailyAppreciationRepository;
	    private ClassRepository classRepository;
	    
	    private TestRepository testRepository;
	    private QuestionRepository questionRepository;
	    private CorrectAnswerRepository correctAnswerRepository;
	    private MultipleChoiceOptionRepository multipleChoiceOptionRepository;
	    private AnswerRepository answerRepository;
	    private TestResultRepository testResultRepository;
	    private TestResultGradeRepository testResultGradeRepository;
	    private LessonRepository lessonRepository;
	    private LessonRecordRepository lessonRecordRepository;
	    private SocioEmotionalTestQuestionRepository socioEmotionalTestQuestionRepository;
	    private SocioEmotionalTestQuestionOptionRepository socioEmotionalTestQuestionOptionRepository;
	    private SocioEmotionalTestAnswerRepository socioEmotionalTestAnswerRepository;
	    private SocioEmotionalTestResultRepository socioEmotionalTestResultRepository;

	    
	    
	    public TestController(LessonRecordRepository lessonRecordRepository, SocioEmotionalTestResultRepository socioEmotionalTestResultRepository, SocioEmotionalTestAnswerRepository socioEmotionalTestAnswerRepository, SocioEmotionalTestQuestionRepository socioEmotionalTestQuestionRepository, SocioEmotionalTestQuestionOptionRepository socioEmotionalTestQuestionOptionRepository,  LessonRepository lessonRepository, TestResultGradeRepository testResultGradeRepository, TestResultRepository testResultRepository, AnswerRepository answerRepository, TestRepository testRepository, QuestionRepository questionRepository, CorrectAnswerRepository correctAnswerRepository, MultipleChoiceOptionRepository multipleChoiceOptionRepository, ClassRepository classRepository, DailyAppreciationRepository dailyAppreciationRepository, MoodUpdateRepository moodUpdateRepository, QuoteRepository qouteRepository, WallPostRepository wallPostRepository, WallPostAttachmentRepository wallPostAttachmentRepository, WallPostRequestRepository wallPostRequestRepository, AvatarRepository avatarRepository,
	    		InstructorRepository instructorRepository, StudentRepository studentRepository,AccountRepository accountRepository, BCryptPasswordEncoder bCryptPasswordEncoder) {
	    	
	    	this.lessonRecordRepository = lessonRecordRepository;
	    	this.socioEmotionalTestQuestionRepository = socioEmotionalTestQuestionRepository;
	    	this.socioEmotionalTestQuestionOptionRepository = socioEmotionalTestQuestionOptionRepository;
	    	this.socioEmotionalTestAnswerRepository = socioEmotionalTestAnswerRepository;
	    	this.socioEmotionalTestResultRepository = socioEmotionalTestResultRepository;
	    	
	    	this.testResultRepository = testResultRepository;
	    	this.answerRepository = answerRepository;
	    	this.testRepository = testRepository;
	    	this.lessonRepository = lessonRepository;
	    	
	    	this.questionRepository  = questionRepository;
	    	this.correctAnswerRepository = correctAnswerRepository;
	    	this.multipleChoiceOptionRepository = multipleChoiceOptionRepository;
	    	this.testResultGradeRepository = testResultGradeRepository;
	    	
	    	this.classRepository = classRepository;
	    	this.qouteRepository = qouteRepository;
	    	this.wallPostRepository = wallPostRepository;
	    	this.wallPostAttachmentRepository = wallPostAttachmentRepository;
	    	this.wallPostRequestRepository = wallPostRequestRepository;
	    	this.avatarRepository = avatarRepository;
	    	this.bCryptPasswordEncoder= bCryptPasswordEncoder;
	    	this.instructorRepository = instructorRepository;
	    	this.studentRepository = studentRepository;
	    	this.accountRepository = accountRepository;
	    	this.moodUpdateRepository = moodUpdateRepository;
			this.dailyAppreciationRepository = dailyAppreciationRepository;
		}
	    
	    @GetMapping("/get/test")   
	    public ResponseEntity<TestDataWrapper> getTest(@RequestParam(value="lesson_id", defaultValue="aEn24") Long lesson_id){
	    	
	    	TestDataWrapper data = new TestDataWrapper();
	    	
	    	Lesson l = lessonRepository.getOne(lesson_id);
	    	
	    	if(l  == null) {
	    		
	    		return new ResponseEntity<TestDataWrapper>(HttpStatus.NOT_FOUND);
	    		
	    	}
	    	
	    	if(l.getTest_id() == 0) {
	   			 throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The Test is not found!!!.");
	    	}
	    	
	    	Test test = testRepository.getOne(l.getTest_id());
	    	
	    	if(test == null) {
	    		
	    		return new ResponseEntity<TestDataWrapper>(HttpStatus.NOT_FOUND);
	    		
	    	}
	    	
	    	data.setTest(test);
	    	
	    	List<Question> questions = questionRepository.findByTestId(l.getTest_id());
	    	
	    	for(Question q: questions) {
	    		
	    		QuestionDataWrapper qdw = new QuestionDataWrapper();
	    		
	    		qdw.setQuestion(q);
	    		
	    		if(test.getIsGraded() && correctAnswerRepository.findByQuestionId(q.getQuestion_id()) != null) {
	    			
	    			
	    			qdw.setCorrectAnswer(correctAnswerRepository.findByQuestionId(q.getQuestion_id()));
	    			
	    			if(q.getQuestion_type().equals("multiple")) {
	    				
	    				qdw.setOptions(multipleChoiceOptionRepository.findByQuestionId(q.getQuestion_id()));
	    				
	    			}
	    			
	    		}
	    		
	    		data.questions.add(qdw);
	    		
	    	}
	    	
    	   	return new ResponseEntity<TestDataWrapper>(data, HttpStatus.OK);
	    		    	
	    }
	    
	    @GetMapping("/get/socio/emotional/test")   
	    public ResponseEntity<SocioEmotionalTestDataWrapper> getSocioEmotionalTest(){
	    	
	    	SocioEmotionalTestDataWrapper s = new SocioEmotionalTestDataWrapper();
	    	s.setOptions(socioEmotionalTestQuestionOptionRepository.findAll());
	    	s.setQuestions(socioEmotionalTestQuestionRepository.findAll());
	    	
    	   	return new ResponseEntity<SocioEmotionalTestDataWrapper>(s, HttpStatus.OK);
	    		    	
	    }
	    
	    
	    @GetMapping("/check/socio/emotional/test")   
	    public ResponseEntity<Lesson> checkSocioEmotionalTest(@RequestParam(value="student_id", defaultValue="aEn24") Long student_id){
	    
	    	//Get student
	      	Student student = studentRepository.getOne(student_id);
			
	        if(student == null) {
	        	
	        	return new ResponseEntity<Lesson>(HttpStatus.BAD_REQUEST);
	        	
	        }
	        
	        SocioEmotionalTestResult t = socioEmotionalTestResultRepository.findMostRecentByStudentId(student_id);
			
			//If student has not taken socio emotional test ever then they need to take it 
			if(t == null) {
				return new ResponseEntity<Lesson>(new Lesson(), HttpStatus.OK);
				
			}
	       
	    	
	        //Get all past lessons this user has completed
	    	List<Lesson> completedLessons = new ArrayList<>();
	    	
	    	List<Lesson> allLessons = lessonRepository.findByGradeId(student.getGrade_id());
	    	
	    	//Get lesson associated with each record
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(student.getStudent_id())) {
	    			    		
	    		Lesson _l = lessonRepository.getOne(l.getLesson_id());
	    		
	    		if(_l != null) {
	    			
	    			completedLessons.add(_l);
	    			
	    		}
	    			    		
	    	}
	    
	    	
	    	
	    	int highest_lesson_completed = 1;
	    	
	    	//Find highest completed lesson
	    	for(Lesson l:completedLessons) {
	    		
	    		if(l.getLesson_index() > highest_lesson_completed) {
	    			
	    			highest_lesson_completed=l.getLesson_index();
	    			
	    		}
	    		
	    	}
	    	
	    	//If lesson is a multiple of 30
	    	if(highest_lesson_completed%30 == 0) {
	    		
	    		
	    		for(Lesson l:allLessons) {
		    		
		    		if(l.getLesson_index() == (highest_lesson_completed) ) {
		    			
		    			//If the student has already taken the sc test while on this lesson
		    			if(l.getLesson_id() == t.getLast_completed_lesson_id()) {
		    				
		    				return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
		    				
		    			}else {
		    				
		    				return new ResponseEntity<Lesson>(new Lesson(), HttpStatus.OK);
		    				
		    			}
		    			
		    			
		    		}
		    		
		    	}
	    		
	    		return new ResponseEntity<Lesson>(HttpStatus.OK);
		    	   		
	    		
	    	}else {
	    		
	    	   	return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	    		
	    	}
	        	
	    }

	    
	    @PostMapping("/submit/socio/emotional/test")
	    @ResponseBody
	    public ResponseEntity<SocioEmotionalTestResult> submitTest(@RequestBody SocioEmotionalTestResultWrapper request) {
	    	
	    	Student student = studentRepository.getOne(request.getStudent_id());
	    			
	        if(student == null) {
	        	
	        	return new ResponseEntity<SocioEmotionalTestResult>(HttpStatus.NOT_FOUND);
	        	
	        }
	       
	        
	        
	        int total_score = 0;
	        	        
	        for(SocioEmotionalTestAnswer a: request.getAnswers()) {
	        	
	        	SocioEmotionalTestQuestion q = socioEmotionalTestQuestionRepository.getOne(a.getSocio_emotional_test_question_id());
	        	
	        	if(q == null) {
	        //		System.out.println("Question is NULL!!");

	        	}
	        	
	        	SocioEmotionalTestQuestionOption o = socioEmotionalTestQuestionOptionRepository.getOne(a.getSocio_emotional_test_question_option_id());
	        	
	        	if(q.isReversed()) {
	        		
	        //		System.out.println("Question is reversed id: " + q.getSocio_emotional_test_question_id() );
	        		
	        		total_score += o.getReverse_weight();
	        		
	      //  		System.out.println("Question weight is " + o.getReverse_weight() );

	        		
	        	}else {
	        		
	        //		System.out.println("Question is not reversed id: " + q.getSocio_emotional_test_question_id() );

	        		
	        		total_score += o.getWeight();
	        		
	        //		System.out.println("Question weight is " + o.getWeight() );

	        		
	        	}
	        	
	        }
	        
	    	
	    	List<Lesson> completedLessons = new ArrayList<>();
	    	
	    	List<Lesson> allLessons = lessonRepository.findByGradeId(student.getGrade_id());
	    	
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(student.getStudent_id())) {
	    			    		
	    		Lesson _l = lessonRepository.getOne(l.getLesson_id());
	    		
	    		if(_l != null) {
	    			
	    			completedLessons.add(_l);
	    			
	    		}
	    			    		
	    	}
	    	
	    	int highest_lesson_completed = 1;
	    	
	    	for(Lesson l:completedLessons) {
	    		
	    		if(l.getLesson_index() > highest_lesson_completed) {
	    			highest_lesson_completed=l.getLesson_index();
	    		}
	    		
	    	}
	    	
	    	
	        SocioEmotionalTestResult t = new SocioEmotionalTestResult();

	    		    	
	    	for(Lesson l:allLessons) {
	    		
	    		if(l.getLesson_index() == (highest_lesson_completed) ) { //If this lesson is the next lesson
	    			t.setLast_completed_lesson_id(l.getLesson_id());
	    		}
	    		
	    	}
	    
	        
	        
	        t.setStudent_id(request.getStudent_id());
	        
	        t.setScore(total_score);
	        
	        t = socioEmotionalTestResultRepository.save(t);
	        
	        for(SocioEmotionalTestAnswer a: request.getAnswers()) {
	        	
	        	a.setSocio_emotional_test_result_id(t.getSocio_emotional_test_result_id());
	        	
	        	socioEmotionalTestAnswerRepository.save(a);
	        	
	        }
	        
	        student.setShould_force_socio_emotional_assessment(false);
	        studentRepository.save(student);
	        
	        return new ResponseEntity<SocioEmotionalTestResult>(t,HttpStatus.OK);

	    }
	    
	    @PostMapping("/create/question")
	    @ResponseBody
	    public ResponseEntity<SocioEmotionalTestQuestion> createQuestion(@RequestBody SocioEmotionalTestQuestion request) {
	        
	        return new ResponseEntity<SocioEmotionalTestQuestion>(socioEmotionalTestQuestionRepository.save(request),HttpStatus.OK);

	    }
	    
	    @PostMapping("/submit/test")
	    @ResponseBody
	    public ResponseEntity<TestResultGrade> submitTest(@RequestBody TestResultDataWrapper request) {
	    	
	    	Test test = testRepository.getOne(request.getTest_id());
	    			
	        if(test == null) {
	      //  	System.out.println("Test does not exist. Cannot grade!");
	        	return new ResponseEntity<TestResultGrade>(HttpStatus.NOT_FOUND);
	        }	        
	        
	        TestResult tr = testResultRepository.findMostRecentByStudent(test.getTest_id(), request.getStudent_id());
	        
	        if(tr == null) {
		        tr = new TestResult();
	        }
	        
	        tr.setTest_id(test.getTest_id());
	        
	        tr.setStudent_id(request.getStudent_id());
	        
	        tr.setCreatedAt(new Date());
	        
	        TestResult testResult = testResultRepository.save(tr);
	        
	        
	        int total_question_count = questionRepository.findByTestId(test.getTest_id()).size();
	        
	        int correct_answer_count = 0;	        
	        
	        for(Answer a: request.getAnswers()) {
	        	
	        	Answer answer = answerRepository.findByTestResultIdAndQuestionId(testResult.getTest_result_id(), a.getQuestion_id());
	        	
	        	if(answer != null) {
	        		a.setAnswer_id(answer.getAnswer_id());
	        	}
	        	
	        	a.setTest_result_id(testResult.getTest_result_id());
	        	
	        	answerRepository.save(a);
	        	
	        	CorrectAnswer c = correctAnswerRepository.findByQuestionId(a.getQuestion_id());
	        	
	        	if(c == null) {
	        //		System.out.println("Missing a correct answer for question " + a.getQuestion_id());
		        	return new ResponseEntity<TestResultGrade>(HttpStatus.NOT_FOUND);
		        	
		        }
	        	
	        	if(a.getAnswer_text().toLowerCase().trim().equals(c.getCorrect_answer_text().toLowerCase().trim())) {
	        		
	        		//
	        		
	        		correct_answer_count+=1;
	        	}
	        	
	        }
	        
	        float grade = 0f;
	        
	        if(correct_answer_count > 0) {
	        	
	        	grade = ((float)correct_answer_count/(float)total_question_count);
	        	
	        }else {
	        	grade = 0f;
	        }
	        
	        
	        TestResultGrade testResultGrade = testResultGradeRepository.findByTestResultId(testResult.getTest_result_id());
	        
	        if(testResultGrade == null) {
	        	testResultGrade = new TestResultGrade();
	        }
	        
	        testResultGrade.setGrade(grade);
	        
	        testResultGrade.setTest_result_id(testResult.getTest_result_id());

	        TestResultGrade result = testResultGradeRepository.save(testResultGrade);
	        
	        LessonRecord l = lessonRecordRepository.findByStudentIdAndLessonId(request.getStudent_id(),request.getLesson_id());

	        if(l == null) {
	        	l = new LessonRecord();
	        }
	        
	        l.setStudent_id(request.getStudent_id());
	        l.setLesson_id(request.getLesson_id());
	        l.setCreatedAt(new Date());

	        lessonRecordRepository.save(l);
	        
	        return new ResponseEntity<TestResultGrade>(result,HttpStatus.OK);

	    }
	    
	    
	    @PostMapping("/create/test")
	    @ResponseBody
	    public ResponseEntity<Test> createTest(@RequestBody TestDataWrapper request) {
	    	
	    	Test test = testRepository.save(request.getTest());
	    	
	    	if(lessonRepository.existsById(request.getLesson_id())) {
	    		
		    	Lesson lesson = lessonRepository.getOne(request.getLesson_id());
		    	lesson.setTest_id(test.getTest_id());
		    	lessonRepository.save(lesson);
		    	
	    	}
	    	
	    		    			
	        for(QuestionDataWrapper q: request.questions) {
	        	
	        	q.getQuestion().setTest_id(test.getTest_id());
	        	
	        	Question question =  questionRepository.save(q.getQuestion());
	        	
	        	q.getCorrectAnswer().setQuestion_id(question.getQuestion_id());
	        	
	        	correctAnswerRepository.save(q.getCorrectAnswer());
	        	
	        	for(MultipleChoiceOption o:q.getOptions()) {
	        		
	        		o.setQuestion_id(question.getQuestion_id());
	        		multipleChoiceOptionRepository.save(o);
	        		
	        	}
	        	
	        }
	       
	        return new ResponseEntity<Test>(test,HttpStatus.OK);

	    }
	    
	    
	    @PostMapping("/update/test")
	    @ResponseBody
	    public ResponseEntity<Test> updateTest(@RequestBody TestDataWrapper request) {
	    	
	    	Test test = testRepository.save(request.getTest());
	    	
	    	for(Question q: questionRepository.findByTestId(test.getTest_id())) {
	    		
	    		correctAnswerRepository.delete(correctAnswerRepository.findByQuestionId(q.getQuestion_id()));
	    		
	    		multipleChoiceOptionRepository.deleteAll(multipleChoiceOptionRepository.findByQuestionId(q.getQuestion_id()));
	    		
	    		questionRepository.delete(q);
	    		
	    	}
	    			    	
	 	    			
	        for(QuestionDataWrapper q: request.questions) {
	        	
	        	q.getQuestion().setTest_id(test.getTest_id());
	        	
	        	Question question =  questionRepository.save(q.getQuestion());
	        	
	        	q.getCorrectAnswer().setQuestion_id(question.getQuestion_id());
	        	
	        	correctAnswerRepository.save(q.getCorrectAnswer());
	        	
	        	for(MultipleChoiceOption o:q.getOptions()) {
	        		
	        		o.setQuestion_id(question.getQuestion_id());
	        		
	        		multipleChoiceOptionRepository.save(o);
	        		
	        	}
	        	
	        }
	       
	        return new ResponseEntity<Test>(test,HttpStatus.OK);

	    }
	    
	    
	    @GetMapping("/delete/test")   
	    public ResponseEntity<Test> deleteTest(@RequestParam(value="test_id", defaultValue="aEn24") Long test_id){
	    	
	    	
	    	Test test = testRepository.getOne(test_id);
	    	
	    	if(test == null) {
	    		
	    		return new ResponseEntity<Test>(HttpStatus.NOT_FOUND);
	    		
	    	}
	    	
	    	testRepository.deleteById(test_id);
	    	
	    	for(Question q: questionRepository.findByTestId(test_id)) {
	    		
	    		correctAnswerRepository.delete(correctAnswerRepository.findByQuestionId(q.question_id));
	    		
	    		multipleChoiceOptionRepository.deleteAll(multipleChoiceOptionRepository.findByQuestionId(q.getQuestion_id()));
	    		
	    		questionRepository.deleteById(q.getQuestion_id());    		
	    		
	    	}
	    	
    	   	return new ResponseEntity<Test>(new Test(), HttpStatus.OK);
	    		    	
	    } 
	    
	    //Retrieve test, grade it, determine if it has been 30 days or lessons since user last took test
	    
	    
	   
	    
}
