package com.infinite.focus.server.lessons;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import org.springframework.beans.factory.annotation.Autowired;
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.RequestHeader;
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.Account;
import com.infinite.focus.server.auth.AccountDataWrapper;
import com.infinite.focus.server.auth.AccountRepository;
import com.infinite.focus.server.auth.Admin;
import com.infinite.focus.server.auth.AdminRepository;
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.SecurityConstants;
import com.infinite.focus.server.auth.Student;
import com.infinite.focus.server.auth.StudentRepository;
import com.infinite.focus.server.googleapis.services.youtube.YouTubeDurationUtils;
import com.infinite.focus.server.googleapis.services.youtube.YouTubeService;
import com.infinite.focus.server.googleapis.services.youtube.YouTubeVideoDetails;
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.students.Class;
import com.infinite.focus.server.students.ClassRepository;
import com.infinite.focus.server.tests.AnswerRepository;
import com.infinite.focus.server.tests.CorrectAnswerRepository;
import com.infinite.focus.server.tests.MultipleChoiceOptionRepository;
import com.infinite.focus.server.tests.QuestionRepository;
import com.infinite.focus.server.tests.Test;
import com.infinite.focus.server.tests.TestRepository;
import com.infinite.focus.server.tests.TestResult;
import com.infinite.focus.server.tests.TestResultDataWrapper;
import com.infinite.focus.server.tests.TestResultGradeRepository;
import com.infinite.focus.server.tests.TestResultRepository;
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;

import io.jsonwebtoken.Jwts;

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


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

public class LessonController {
	
	 	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 AdminRepository adminRepository;
	    
	    @Autowired
	    private YouTubeService youTubeService;
	    
	    public LessonController(AdminRepository adminRepository, LessonRecordRepository lessonRecordRepository, 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.adminRepository = adminRepository;
	    	this.lessonRecordRepository = lessonRecordRepository;
	    	this.lessonRepository = lessonRepository;
	    	this.testResultRepository = testResultRepository;
	    	this.answerRepository = answerRepository;
	    	this.testRepository = testRepository;
	    	
	    	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/lessons")   
	    public ResponseEntity<List<LessonTestWrapper>> getLessons(@RequestParam(value="grade_id", defaultValue="aEn24") Long grade_id){
	    	
	    List<LessonTestWrapper> lessons = new ArrayList<>();
	    for(Lesson l: lessonRepository.findByGradeId(grade_id)) {
	    	
	    	LessonTestWrapper ltw = new LessonTestWrapper();
	    	ltw.setLesson(l);
	    
	    	ltw.setHasTest(false);
	    	
	    	if(testRepository.existsById(l.getTest_id())) {
	    		
	    //		System.out.println("Test was not nul!!!");
	    	
	    	ltw.setTest(testRepository.getOne(l.getTest_id()));
	    	ltw.setHasTest(true);
	    	
	    	}
	    	
	    	lessons.add(ltw);
	    	
	    }
	    	
    	   	return new ResponseEntity<List<LessonTestWrapper>>(lessons, HttpStatus.OK);
	    }
	    
	  
	    
	    @PostMapping("/create/lesson")
	    @ResponseBody
	    public ResponseEntity<Lesson> createLesson(@RequestBody Lesson request, @RequestHeader(SecurityConstants.HEADER_STRING) String token ) {
	    	
	    	 if (token != null && !token.contains("undefined")) {
	               
	               
	               //Parse token
	               String user = Jwts.parser()
	                       .setSigningKey(SecurityConstants.SECRET)
	                       .parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, ""))
	                       .getBody()
	                       .getSubject();
	               
	               //If token was successfully parsed
	               if (user != null) {
	                  
	         //          System.out.println(user);
	                   
	                   //Find account for parsed user name
	                   Account a = accountRepository.findByUsername(user);
	                   
	                   //If account is null return error code to client
	                   if(a == null) {
	           	   			return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	                   }
	                   
	                   
	                   Admin ad = adminRepository.findByUserName(user);
	                   
	                  if(ad != null) {
	                		
	          	    	Lesson highest_lesson = lessonRepository.findHighestLessonByGradeId(request.getGrade_id());
	          	    	
	          	    	if(highest_lesson == null) {
	          	    		request.setLesson_index(1);
	          	    	}else {
	          	    		request.setLesson_index(highest_lesson.getLesson_index() + 1);
	          	    	}
	          	    	
	          	    	 long duration = getYouTubeVideoDurationInSeconds(request.getVideo_url());
		      				
	                	  request.setVideo_duration(duration);
	                	  
	          	        return new ResponseEntity<Lesson>(lessonRepository.save(request),HttpStatus.OK);
	                	   
	                	   
	                	   	                   
	                   }
	                   
	                   
	                   	                  
	           		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
		
	               }
	               
	         		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);

	           }else{
	        	   		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	           }          
	    

	    }
	    
	    
	    @PostMapping("/update/lesson")
	    @ResponseBody
	    public ResponseEntity<Lesson> updateLesson(@RequestBody Lesson request, @RequestHeader(SecurityConstants.HEADER_STRING) String token) {
	  
	    	
	    	 if (token != null && !token.contains("undefined")) {
	               
	               
	               //Parse token
	               String user = Jwts.parser()
	                       .setSigningKey(SecurityConstants.SECRET)
	                       .parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, ""))
	                       .getBody()
	                       .getSubject();
	               
	               //If token was successfully parsed
	               if (user != null) {
	                  
	           //        System.out.println(user);
	                   
	                   //Find account for parsed user name
	                   Account a = accountRepository.findByUsername(user);
	                   
	                   //If account is null return error code to client
	                   if(a == null) {
	           	   			return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	                   }
	                   
	                   
	                   Admin ad = adminRepository.findByUserName(user);
	                   
	                  if(ad != null) {
	                		
	                	  long duration = getYouTubeVideoDurationInSeconds(request.getVideo_url());
	      				
	                	  request.setVideo_duration(duration);
	                	  
	          	        return new ResponseEntity<Lesson>(lessonRepository.save(request),HttpStatus.OK);
              	   
	                	   	                   
	                   }
	                   
	                   
	                   	                  
	           		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
		
	               }
	               
	         		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);

	           }else{
	        	   		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	           }          
	    

	    	
	    	

	    }
	    
	    
	    @GetMapping("/delete/lesson")   
	    public ResponseEntity<Lesson> deleteLesson(@RequestParam(value="lesson_id", defaultValue="aEn24") Long lesson_id, @RequestHeader(SecurityConstants.HEADER_STRING) String token){
    	   	
	    	
	    	 if (token != null && !token.contains("undefined")) {
	               
	               
	               //Parse token
	               String user = Jwts.parser()
	                       .setSigningKey(SecurityConstants.SECRET)
	                       .parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, ""))
	                       .getBody()
	                       .getSubject();
	               
	               //If token was successfully parsed
	               if (user != null) {
	                  
	              //     System.out.println(user);
	                   
	                   //Find account for parsed user name
	                   Account a = accountRepository.findByUsername(user);
	                   
	                   //If account is null return error code to client
	                   if(a == null) {
	           	   			return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	                   }
	                   
	                   
	                   Admin ad = adminRepository.findByUserName(user);
	                   
	                  if(ad != null) {
	                	  
	                	  lessonRepository.deleteById(lesson_id);
	                		
	          	        return new ResponseEntity<Lesson>(new Lesson(),HttpStatus.OK);
            	   
	                	   	                   
	                   }
	                   
	                   
	                   	                  
	           		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
		
	               }
	               
	         		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);

	           }else{
	        	   		return new ResponseEntity<Lesson>(HttpStatus.NOT_FOUND);
	           }          
	    

	    	
	    	
	    	
	    }
	    
	    @PostMapping("/create/record")
	    @ResponseBody
	    public ResponseEntity<LessonRecord> updateLesson(@RequestBody LessonRecord request) {
	        return new ResponseEntity<LessonRecord>(lessonRecordRepository.save(request),HttpStatus.OK);

	    }
	    
	    @GetMapping("/get/records")   
	    public ResponseEntity<List<LessonRecordWrapper>> getRecords(@RequestParam(value="student_id", defaultValue="aEn24") Long student_id){
	    	
	    	List<LessonRecordWrapper> list = new ArrayList<>();
	    	
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(student_id)) {
	    		
	    		LessonRecordWrapper lrw = new LessonRecordWrapper();
	    		
	    		lrw.setLessonRecord(l);
	    		
	    		Lesson lesson = lessonRepository.getOne(l.getLesson_id());
	    		
	    		if(lesson == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		lrw.setLesson(lesson);
	    		
	    		Test test = testRepository.getOne(lesson.getTest_id());
	    		
	    		if(test == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		TestResult testResult = testResultRepository.findMostRecentByStudent(test.getTest_id(), student_id);
	    		
	    		if(testResult != null) {
	    			lrw.setAnswers(answerRepository.findByTestResultId(testResult.getTest_result_id()));
	    			lrw.setGrade(testResultGradeRepository.findByTestResultId(testResult.getTest_result_id()).getGrade());
	    		}
	    		
	    		list.add(lrw);
	    		
	    		
	    	}
   		    	
    	   	return new ResponseEntity<List<LessonRecordWrapper>>(list, HttpStatus.OK);
	    }
	    
	
	    
	    
@GetMapping("/get/next/lesson")   
   public ResponseEntity<LessonWrapper> getNextLesson(@RequestParam(value="student_id", defaultValue="aEn24") Long student_id){
	    	
			LessonWrapper lesson = new LessonWrapper();
	    	lesson.setStatus("LESSON_COMPLETE");

	    	Student student = studentRepository.getOne(student_id);
	    	
	    	if(student == null) {
    			
	    		return new ResponseEntity<LessonWrapper>(HttpStatus.NOT_FOUND);
    			
    		}
	    	
	    	List<Lesson> completedLessons = new ArrayList<>();
	    	List<Lesson> allLessons = lessonRepository.findByGradeId(student.getGrade_id());
	    	
	    	if(allLessons == null || allLessons.isEmpty()) {
   			    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Sorry, no lessons are available at the moment. Please check back later.");
	    	}
	    	
	    	
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(student_id)) {
	    			    		
	    		Lesson _l = lessonRepository.findByLessonId(l.getLesson_id());
	    		
	    		if(_l != null) {
	    			
	    			completedLessons.add(_l);
	    			
	    		}
	    			    		
	    	}
	    	
	    	if(completedLessons == null || completedLessons.isEmpty()) {
	    		lesson.setLesson_id(allLessons.get(0).getLesson_id());
    			lesson.setGrade_id(allLessons.get(0).getGrade_id());
    			lesson.setGuide_post_text(allLessons.get(0).getGuide_post_text());
    			lesson.setLesson_index(allLessons.get(0).getLesson_index());
    			lesson.setTest_id(allLessons.get(0).getTest_id());
    			lesson.setVideo_url(allLessons.get(0).getVideo_url());
    			lesson.setStatus("HAS_NEXT_LESSON");
        	   	return new ResponseEntity<LessonWrapper>(lesson, HttpStatus.OK);
	    	}
	    	
    	//	System.out.println("Printing all lessons for grade");

	    	for(Lesson l:allLessons) {
	    		
	    //		System.out.println("lesson_id" + l.getLesson_id() + " guide_post_text " +l.getGuide_post_text());
	    			    		
	    	}
	    	
	    //	System.out.println("Printing all completed lessons for student");

	    	for(Lesson l:completedLessons) {
	    		
	    //		System.out.println("lesson_id" + l.getLesson_id() + " guide_post_text " +l.getGuide_post_text());
	    			    		
	    	}
	    	
	    	int highest_lesson = 0;

	    	for(Lesson l: allLessons) {
	    		
	    		if(l.getLesson_index() > highest_lesson) {
	    			highest_lesson=l.getLesson_index();
	    		}
	    		
	    	}

	    	int highest_lesson_completed = 0;
	    	
	    	for(Lesson l:completedLessons) {
	    		
	    		if(l.getLesson_index() > highest_lesson_completed) {
	    			highest_lesson_completed=l.getLesson_index();
	    		}
	    		
	    	}
	    	
	    	if(highest_lesson == highest_lesson_completed) {
	   			    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Hurray, you have completed all lessons!!");
	    	}
	    	
	    	
	    	
	    	
	    	boolean isLessonIndexNotFound = true;
	    	
	    	for(Lesson l:allLessons) {
	    		
	    		if(l.getLesson_index() == (highest_lesson_completed+1) ) { //If this lesson is the next lesson
	    			isLessonIndexNotFound = false;
	    			lesson.setLesson_id(l.getLesson_id());
	    			lesson.setGrade_id(l.getGrade_id());
	    			lesson.setGuide_post_text(l.getGuide_post_text());
	    			lesson.setLesson_index(l.getLesson_index());
	    			lesson.setTest_id(l.getTest_id());
	    			lesson.setVideo_url(l.getVideo_url());
	    			lesson.setStatus("HAS_NEXT_LESSON");
	    		}
	    		
	    	}
	    
	    	if(isLessonIndexNotFound) {
	    		lesson.setLesson_id(allLessons.get(0).getLesson_id());
    			lesson.setGrade_id(allLessons.get(0).getGrade_id());
    			lesson.setGuide_post_text(allLessons.get(0).getGuide_post_text());
    			lesson.setLesson_index(allLessons.get(0).getLesson_index());
    			lesson.setTest_id(allLessons.get(0).getTest_id());
    			lesson.setVideo_url(allLessons.get(0).getVideo_url());
    			lesson.setStatus("HAS_NEXT_LESSON");
	    	}
	    	
    	   	return new ResponseEntity<LessonWrapper>(lesson, HttpStatus.OK);
	    }
	    
	    
		@GetMapping("/set-video-duration-in-lessons-in-seconds")
		public ResponseEntity<List<Lesson>> setVideoDurationInLessonsInSe() {
			
			List<Lesson> allLessons = lessonRepository.findAll();
			
			for(Lesson l:allLessons) {
				
				long duration = getYouTubeVideoDurationInSeconds(l.getVideo_url());
				
				l.setVideo_duration(duration);
				lessonRepository.save(l);
				
			}
			
			return new ResponseEntity<List<Lesson>>(allLessons, HttpStatus.OK);
		}
		
		
		public Long getYouTubeVideoDurationInSeconds(String video_url) {

			String video_id = getVideoIdFromUrl(video_url);
			
			Long duration = 0L;
			
			try {
				YouTubeVideoDetails youTubeVideoDetails = youTubeService.getYouTubeVideoDetailsByVideoId(video_id);
				String youTubeVideDuration = youTubeVideoDetails.getItems().get(0).getContentDetails().getDuration();
				//System.out.println(youTubeVideDuration);
				//System.out.println(YouTubeDurationUtils.convertYouTubeDuration(youTubeVideDuration));
				//System.out.println(YouTubeDurationUtils.convertYouTubeDurationInSeconds(youTubeVideDuration));
				
				duration = YouTubeDurationUtils.convertYouTubeDurationInSeconds(youTubeVideDuration);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			//System.out.println(video_id);
			
			return duration;
		}
		
		public String getVideoIdFromUrl(String video_url) {

			// video_url = "https://www.youtube.com/watch?v=SVNICEz5IoM";

			video_url = video_url.trim();
			
			String video_id = "error";

			String pattern = "(?<=watch\\?v=|/videos/|embed\\/|youtu.be\\/|\\/v\\/|\\/e\\/|watch\\?v%3D|watch\\?feature=player_embedded&v=|%2Fvideos%2F|embed%\u200C\u200B2F|youtu.be%2F|%2Fv%2F)[^#\\&\\?\\n]*";

			Pattern compiledPattern = Pattern.compile(pattern);
			Matcher matcher = compiledPattern.matcher(video_url); 
			
			if (matcher.find()) {
				video_id = matcher.group();
			}
			
			return video_id;
		}
	    
}
