package com.infinite.focus.server.wall;

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.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.AccountRepository;
import com.infinite.focus.server.auth.Admin;
import com.infinite.focus.server.auth.AdminRepository;
import com.infinite.focus.server.auth.AuthenticationController;
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.Message;
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.home.Quote;
import com.infinite.focus.server.lessons.Lesson;
import com.infinite.focus.server.students.Class;

import io.jsonwebtoken.Jwts;

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

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

public class WallPostController {

	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 AdminRepository adminRepository;
	private TopPicksRepository topPicksRepository;
	
	public WallPostController(AdminRepository adminRepository, WallPostRepository wallPostRepository,
			WallPostAttachmentRepository wallPostAttachmentRepository,
			WallPostRequestRepository wallPostRequestRepository, AvatarRepository avatarRepository,
			InstructorRepository instructorRepository, StudentRepository studentRepository,
			AccountRepository accountRepository,TopPicksRepository topPicksRepository, BCryptPasswordEncoder bCryptPasswordEncoder) {

		this.adminRepository = adminRepository;
		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.topPicksRepository = topPicksRepository;

	}

	@GetMapping("/respond/request")
	public ResponseEntity<WallPost> respondRequest(
			@RequestParam(value = "wall_post_request_id", defaultValue = "aEn24") Long wall_post_request_id,
			@RequestParam(value = "response", defaultValue = "aEn24") Boolean response) {

		WallPostRequest w = wallPostRequestRepository.getOne(wall_post_request_id);

		if (w == null) {
			return new ResponseEntity<WallPost>(HttpStatus.CONFLICT);
		}

		WallPost p = wallPostRepository.getOne(w.getWall_post_id());

		if (p == null) {
			return new ResponseEntity<WallPost>(HttpStatus.CONFLICT);
		}

		if (response) {

			wallPostRequestRepository.delete(w);
			p.setIsActive(true);
			return new ResponseEntity<WallPost>(wallPostRepository.save(p), HttpStatus.OK);

		} else {

			wallPostRequestRepository.delete(w);
			wallPostRepository.delete(p);
			return new ResponseEntity<WallPost>(p, HttpStatus.OK);

		}

	}

	@GetMapping("/add/like")
	public ResponseEntity<WallPost> addLike(
			@RequestParam(value = "wall_post_id", defaultValue = "aEn24") Long wall_post_id) {

		WallPost wp = wallPostRepository.getOne(wall_post_id);

		if (wp == null) {
			return new ResponseEntity<WallPost>(HttpStatus.NOT_FOUND);
		}

		wp.setLikes(wp.getLikes() + 1);

		return new ResponseEntity<WallPost>(wallPostRepository.save(wp), HttpStatus.OK);
	}

	@GetMapping("/get/requests")
	public ResponseEntity<List<WallPostRequestWrapper>> getRequests(
			@RequestParam(value = "instructor_id", defaultValue = "aEn24") Long instructor_id) {

		List<WallPostRequestWrapper> list = new ArrayList<>();

		for (WallPostRequest r : wallPostRequestRepository.findByInstructor(instructor_id)) {

			WallPostRequestWrapper rw = new WallPostRequestWrapper();
			rw.setWallPostRequest(r);

			WallPost wp = (wallPostRepository.getOne(r.getWall_post_id()));
			WallPostWrapper wr = new WallPostWrapper();
			wr.setWallPost(wp);
			wr.setAttachments(wallPostAttachmentRepository.findByWallPost(wp.getWall_post_id()));

			rw.setWallPost(wr);
			list.add(rw);

		}

		return new ResponseEntity<List<WallPostRequestWrapper>>(list, HttpStatus.OK);
	}

	@GetMapping("/get/instructor/posts") // API End point to get user data after authenticated
	public ResponseEntity<List<WallPostProfileWrapper>> getWallPostsByInstructorId(
			@RequestParam(value = "instructor_id", defaultValue = "aEn24") Long instructor_id) {

		List<WallPostProfileWrapper> posts = new ArrayList<>();

		List<WallPost> list = wallPostRepository.findAllActive();

		for (WallPost w : list) {

			if (w.getIsDeleted() != null) {
				if (w.getIsDeleted()) {
					continue;
				}
			}

			WallPostProfileWrapper wr = new WallPostProfileWrapper();
			WallPostWrapper wpr = new WallPostWrapper();
			wpr.setWallPost(w);
			wpr.setAttachments(wallPostAttachmentRepository.findByWallPost(w.getWall_post_id()));
			wr.setWallPost(wpr);

			// System.out.println("Type was " + w.getType());

			if (w.getType().toLowerCase().trim().equals("student")) {
				Student student = studentRepository.getOne(w.getStudent_id());
				if (student.getInstructor_id() != instructor_id) {
					continue;
				}
				wr.setStudent(student);
			}

			if (w.getType().toLowerCase().trim().equals("instructor")) {
				Instructor instructor = instructorRepository.getOne(w.getInstructor_id());
				if (instructor.getInstructor_id() != instructor_id) {
					continue;
				}
				wr.setInstructor(instructor);
			}

			posts.add(wr);

		}

		return new ResponseEntity<List<WallPostProfileWrapper>>(posts, HttpStatus.OK);
	}

	@GetMapping("/get/all/posts") // API End point to get user data after authenticated
	public ResponseEntity<List<WallPostProfileWrapper>> getWallPosts() {

		List<WallPostProfileWrapper> posts = new ArrayList<>();

		List<WallPost> list = wallPostRepository.findAllActive();

		for (WallPost w : list) {

			if (w.getIsDeleted() != null) {
				if (w.getIsDeleted()) {
					continue;
				}
			}

			WallPostProfileWrapper wr = new WallPostProfileWrapper();
			WallPostWrapper wpr = new WallPostWrapper();
			wpr.setWallPost(w);
			wpr.setAttachments(wallPostAttachmentRepository.findByWallPost(w.getWall_post_id()));
			wr.setWallPost(wpr);

			// System.out.println("Type was " + w.getType());

			if (w.getType().toLowerCase().trim().equals("student")) {

				wr.setStudent(studentRepository.getOne(w.getStudent_id()));

			}

			if (w.getType().toLowerCase().trim().equals("instructor")) {

				wr.setInstructor(instructorRepository.getOne(w.getInstructor_id()));

			}

			posts.add(wr);

		}

		return new ResponseEntity<List<WallPostProfileWrapper>>(posts, HttpStatus.OK);
	}

	@PostMapping("/create/post") // API End point for POST request to register a new company
	@ResponseBody
	public ResponseEntity<WallPost> createPost(@RequestBody WallPostWrapper request) { // Capture data sent in Request
																						// Body

		Student student = studentRepository.getOne(request.getWallPost().getStudent_id());

		if (student == null) {
			return new ResponseEntity<WallPost>(HttpStatus.CONFLICT); // if account exists return error
		}

		request.getWallPost().setType("student");
		request.getWallPost().setIsActive(false);
		request.getWallPost().setIsDeleted(false);
		WallPost wallPost = wallPostRepository.save(request.getWallPost());

		for (WallPostAttachment w : request.getAttachments()) {
			w.setWall_post_id(wallPost.getWall_post_id());
			wallPostAttachmentRepository.save(w);
		}

		WallPostRequest wallPostRequest = new WallPostRequest();

		wallPostRequest.setInstructor_id(student.getInstructor_id());
		wallPostRequest.setWall_post_id(wallPost.getWall_post_id());

		wallPostRequestRepository.save(wallPostRequest);

		return new ResponseEntity<WallPost>(wallPost, HttpStatus.OK);

	}

	@PostMapping("/create/post/instructor") // API End point for POST request to register a new company
	@ResponseBody
	public ResponseEntity<WallPost> createPostInstructor(@RequestBody WallPostWrapper request) { // Capture data sent in
																									// Request Body

		request.getWallPost().setType("instructor");
		request.getWallPost().setIsActive(true);
		WallPost wallPost = wallPostRepository.save(request.getWallPost());

		for (WallPostAttachment w : request.getAttachments()) {
			w.setWall_post_id(wallPost.getWall_post_id());
			wallPostAttachmentRepository.save(w);
		}

		return new ResponseEntity<WallPost>(wallPost, HttpStatus.OK);

	}

	@PostMapping("/update/post") // API End point for POST request to register a new company
	@ResponseBody
	public ResponseEntity<WallPost> updatePost(@RequestHeader(SecurityConstants.HEADER_STRING) String token,
			@RequestBody WallPostWrapper request) { // Capture data sent in Request Body
		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) {

				WallPost wp = wallPostRepository.getOne(request.getWallPost().getWall_post_id());

				if (wp == null) {
					throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The post is not found!");
				}

				for (WallPostAttachment w : wallPostAttachmentRepository.findByWallPost(wp.getWall_post_id())) {
					w.setWall_post_id(wp.getWall_post_id());
					wallPostAttachmentRepository.delete(w);
				}

				wp.setText(request.getWallPost().getText());

				for (WallPostAttachment w : request.getAttachments()) {
					w.setWall_post_id(wp.getWall_post_id());
					wallPostAttachmentRepository.save(w);
				}

				return new ResponseEntity<WallPost>(wallPostRepository.save(wp), HttpStatus.OK);

			}

		}
		throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "");
	}

	@PostMapping("/delete/post")
	@ResponseBody
	public ResponseEntity<WallPost> deletePost(
			@RequestParam(value = "wall_post_id", defaultValue = "aEn24") Long wall_post_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<WallPost>(HttpStatus.NOT_FOUND);
				}

				Admin ad = adminRepository.findByUserName(user);

				if (ad != null) {
					WallPost wp = (wallPostRepository.getOne(wall_post_id));

					if (wp == null) {
						throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The post not found!!!.");
					}

					wp.setIsDeleted(true);

					return new ResponseEntity<WallPost>(wallPostRepository.save(wp), HttpStatus.OK);

				}

				Instructor instructor = instructorRepository.findByAccountId(a.getAccount_id());

				if (instructor != null) {
					WallPost wp = (wallPostRepository.getOne(wall_post_id));

					if (wp == null) {
						throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The post not found!!!.");
					}
					/*
					 * if(wp.getInstructor_id() != instructor.getInstructor_id()) { throw new
					 * ResponseStatusException(HttpStatus.UNAUTHORIZED,
					 * "Only the Instructor who approved the post can delete the post or the admin can delete the post."
					 * ); }
					 */
					wp.setIsDeleted(true);

					return new ResponseEntity<WallPost>(wallPostRepository.save(wp), HttpStatus.OK);

				}

				throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Admin or Instructor can delete the post.");

			}

			throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "The user not found!!!.");

		} else {
			return new ResponseEntity<WallPost>(HttpStatus.UNAUTHORIZED);
		}
	}

	@PostMapping("/delete/posts")
	@ResponseBody
	public ResponseEntity<WallPostsDeleteRequest> deletePosts(@RequestBody WallPostsDeleteRequest 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<WallPostsDeleteRequest>(HttpStatus.NOT_FOUND);
				}

				Admin ad = adminRepository.findByUserName(user);

				if (ad != null) {
					ArrayList<Long> wall_post_ids = request.getWall_post_ids();

					if (wall_post_ids == null) {
						throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Require wall_post_ids!!!.");

					}

					if (wall_post_ids.isEmpty()) {
						throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Require wall_post_ids!!!.");
					}

					for (Long wall_post_id : wall_post_ids) {
						WallPost wp = (wallPostRepository.getOne(wall_post_id));

						if (wp == null) {
							throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The post not found!!!.");
						}

						wp.setIsDeleted(true);

						wallPostRepository.save(wp);
					}

					request.setMessage("Posts deleted successfully.");
					return new ResponseEntity<WallPostsDeleteRequest>(request, HttpStatus.OK);

				}

				throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Admin can delete the posts.");

			}

			throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "The user not found!!!.");

		} else {
			return new ResponseEntity<WallPostsDeleteRequest>(HttpStatus.UNAUTHORIZED);
		}
	}

	@PostMapping("/upload/file") // API end point to upload new aid file to server
	@ResponseBody
	public ResponseEntity<WallPostAttachment> uploadImage(@RequestParam(value = "file") MultipartFile file,
			HttpServletResponse response, HttpServletRequest request) throws Exception {

		if (!file.isEmpty()) { // Check if file is empty

			Cloudinary cloudinary = new Cloudinary(ObjectUtils.asMap("cloud_name", "veedbeta", "api_key",
					"843536583549614", "api_secret", "oCK-t2tOxYm_xofyio5PO2k93Us"));

			Map uploadResult = cloudinary.uploader().upload(file.getBytes(), ObjectUtils.emptyMap());

			// System.out.println(uploadResult.toString());

			// System.out.println((String)uploadResult.get("url"));

			WallPostAttachment w = new WallPostAttachment();
			w.setUrl((String) uploadResult.get("url"));

			return new ResponseEntity<WallPostAttachment>(w, HttpStatus.OK);

		} else {

			return new ResponseEntity<WallPostAttachment>(HttpStatus.PARTIAL_CONTENT);

		}

	}

	@GetMapping("/get/post") // API End point to get user data after authenticated
	public ResponseEntity<WallPostProfileWrapper> getWallPostByWallPostId(
			@RequestParam(value = "wall_post_id", defaultValue = "aEn24") Long wall_post_id) {

		WallPost wp = wallPostRepository.getOne(wall_post_id);

		if (wp == null) {
			throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The post not found.");
		}

		if (wp.getIsDeleted() != null) {
			if (wp.getIsDeleted()) {
				throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The post is deleted.");
			}
		}

		WallPostProfileWrapper wr = new WallPostProfileWrapper();
		WallPostWrapper wpr = new WallPostWrapper();
		wpr.setWallPost(wp);
		wpr.setAttachments(wallPostAttachmentRepository.findByWallPost(wp.getWall_post_id()));
		wr.setWallPost(wpr);

		// System.out.println("Type was " + w.getType());

		if (wp.getType().toLowerCase().trim().equals("student")) {
			Student student = studentRepository.getOne(wp.getStudent_id());
			wr.setStudent(student);
		}

		if (wp.getType().toLowerCase().trim().equals("instructor")) {
			Instructor instructor = instructorRepository.getOne(wp.getInstructor_id());
			wr.setInstructor(instructor);
		}

		return new ResponseEntity<WallPostProfileWrapper>(wr, HttpStatus.OK);
	}

	@GetMapping("/get/daily/toppicks")
	public ResponseEntity<TopPicks> getCurrentDailyTopPicks(@RequestHeader(SecurityConstants.HEADER_STRING) String token) {

		AuthenticationController.isAuthenticated(token);
		
		TopPicks topPicks = topPicksRepository.findDailyTopPicks();
		
		if(topPicks == null) {
			throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The daily Top Picks not found!");
		}

		return new ResponseEntity<TopPicks>(topPicks, HttpStatus.OK);

	}

	@DeleteMapping("/delete/toppicks/{top_picks_id}")
	public ResponseEntity<Message> deleteQuote(@RequestHeader(SecurityConstants.HEADER_STRING) String token, @PathVariable(value = "top_picks_id") Long top_picks_id) {

		AuthenticationController.isAuthenticated(token);
		
		TopPicks topPicks = topPicksRepository.getOne(top_picks_id);
		
		if(topPicks == null) {
			throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The Top Picks not found!");
		}
		
		if(topPicks.getIsDailyTopPicks()) {
			throw new ResponseStatusException(HttpStatus.CONFLICT, "The Top Picks is a Daily TopPicks, the Daily TopPicks can not be deleted.");
		}
		
		topPicksRepository.deleteById(top_picks_id);

		Message message = new Message();
		message.setMessage("The TopPicks is deleted successfully.");
		
		return new ResponseEntity<Message>(message, HttpStatus.OK);

	}

	@GetMapping("/get/all/toppicks")
	public ResponseEntity<List<TopPicks>> getAllQuotes(@RequestHeader(SecurityConstants.HEADER_STRING) String token) {

		AuthenticationController.isAuthenticated(token);
		
		return new ResponseEntity<List<TopPicks>>(topPicksRepository.findAllOrderById(), HttpStatus.OK);

	}

	@PostMapping("/create/toppicks")
	@ResponseBody
	public ResponseEntity<TopPicks> createDailyQuote(@RequestHeader(SecurityConstants.HEADER_STRING) String token, @RequestBody TopPicks request) {

		AuthenticationController.isAuthenticated(token);
		
		return new ResponseEntity<TopPicks>(topPicksRepository.save(request), HttpStatus.OK);

	}

	@PostMapping("/update/toppicks")
	@ResponseBody
	public ResponseEntity<TopPicks> updateDailyQuote(@RequestHeader(SecurityConstants.HEADER_STRING) String token, @RequestBody TopPicks request) {

		AuthenticationController.isAuthenticated(token);
		
		TopPicks topPicks = topPicksRepository.getOne(request.getTop_picks_id());
		topPicks.setQoute(request.getQuote());
		topPicks.setCreatedAt(topPicks.getCreatedAt());
		topPicks.setUpdateAt(new Date());
		
		return new ResponseEntity<TopPicks>(topPicksRepository.save(topPicks), HttpStatus.OK);

	}
	
	@GetMapping("/make/daily/toppicks")
	@ResponseBody
	public ResponseEntity<TopPicks> makeDailyQuote() {

		// Retrieve all TopPicks
		List<TopPicks> topPicksList = topPicksRepository.findAll();

		// Set all TopPicks to false
		for (TopPicks topPicks : topPicksList) {
			topPicks.setCreatedAt(topPicks.getCreatedAt());
			topPicks.setUpdateAt(new Date());
			topPicks.setIsDailyTopPicks(false);

			topPicksRepository.save(topPicks);

		}

		// Select random TopPicks
		Random randomizerTopPicks = new Random();

		int random_index_topPicks = randomizerTopPicks.nextInt(topPicksList.size());

		TopPicks random_topPicks = topPicksList.get(random_index_topPicks);
		random_topPicks.setCreatedAt(random_topPicks.getCreatedAt());
		// Set choose TopPicks as daily TopPicks
		random_topPicks.setIsDailyTopPicks(true);
		random_topPicks.setUpdateAt(new Date());
		
		return new ResponseEntity<TopPicks>(topPicksRepository.save(random_topPicks), HttpStatus.OK);

	}
}
