package org.iri_research.renkan.controller;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.codec.binary.Hex;
import org.iri_research.renkan.Constants;
import org.iri_research.renkan.RenkanException;
import org.iri_research.renkan.forms.SpaceForm;
import org.iri_research.renkan.forms.SpaceFormValidator;
import org.iri_research.renkan.models.Space;
import org.iri_research.renkan.repositories.ProjectsRepository;
import org.iri_research.renkan.repositories.SpacesRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefaults;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.HttpClientErrorException;

@Controller
@RequestMapping("/admin")
public class AdminController {

	private final Logger logger = LoggerFactory.getLogger(AdminController.class);
	
	@Autowired
	private SpacesRepository spacesRepository;
	@Autowired
	private ProjectsRepository projectsRepository;
	
    @InitBinder(value={"space"})
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new SpaceFormValidator());
    }
	
	@RequestMapping(value="", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"})
	public String adminIndex() {
				
		return "admin/adminIndex";
	}
	
	@RequestMapping(value="/spaces", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"})
	public String spacesList(
			Model model,
			@PageableDefaults(sort={"created"}, sortDir=Direction.DESC, pageNumber=0, value=Constants.PAGINATION_SIZE) Pageable p,
			HttpServletRequest request) {
		
		Page<Space> page = this.spacesRepository.findAll(p);
		
		model.addAttribute("page", page);
		model.addAttribute("baseUrl", Utils.buildBaseUrl(request));
		model.addAttribute("projectsCount", this.projectsRepository.getCountBySpace());
		
		return "admin/spacesList";
	}
	
	@RequestMapping(value="/spaces/edit/", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"})
	public String editSpace(Model model) {
		return editSpace(model, null);
	}
	
	@RequestMapping(value="/spaces/edit/{spaceId}", method = RequestMethod.GET, produces={"text/html;charset=UTF-8"})
	public String editSpace(Model model, @PathVariable(value="spaceId") String spaceId) {
		
		SpaceForm spaceForm = null;
		
		if(spaceId == null || spaceId.length() == 0 || "_".equals(spaceId)) {
			spaceForm = new SpaceForm();
		}
		else {
			Space space = this.spacesRepository.findOne(spaceId);		
			if(space == null) {
				throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + spaceId + " not found");			
			}
			spaceForm = new SpaceForm(space);
		}
		
		model.addAttribute("space", spaceForm);
		
		return "admin/spaceEdit";
	}
	
	
	@RequestMapping(value="/spaces/save", method = RequestMethod.POST)
	public String saveSpace(Model model, @ModelAttribute("space") @Valid SpaceForm spaceForm, BindingResult bindingResult) {

		logger.debug("space title " + spaceForm.getTitle());
		logger.debug("space description " + spaceForm.getDescription());
		
		if(bindingResult.hasErrors()) {
			return "admin/spaceEdit";
		}
		
		spaceForm.setSpacesRepository(spacesRepository);
		
		try {
			spaceForm.save();
		} catch (RenkanException e) {
			throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + spaceForm.getId() + " not found");
		}
		
		return "redirect:/admin/spaces";
	}
	
	//@RequestMapping(value="/spaces/confirmdelete/{spaceId}", method = RequestMethod.GET)
	//public String askDeleteSpace(Model model, @PathVariable(value="spaceId") String spaceId) {
		
		
	//}
	
	@RequestMapping(value="/spaces/delete/{spaceId}")
	public String deleteSpace(
			HttpServletRequest request,
			Model model,
			@PathVariable(value="spaceId") String spaceId,
			@RequestParam(value="key", required=false) String key,
			@RequestParam(value="salt", required=false) String salt) throws NoSuchAlgorithmException, RenkanException
	{

		if(spaceId == null || spaceId.length() == 0) {
			throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Null or empty space id");
		}
		
		RequestMethod method = RequestMethod.valueOf(request.getMethod());
		
		Map<String, Integer> nbProj = this.projectsRepository.getCountBySpace(Arrays.asList(spaceId));
		if(nbProj.containsKey(spaceId) && nbProj.get(spaceId).intValue()>0) {
			throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "This space have projects");
		}
		
		if(RequestMethod.GET.equals(method)) {

			Space space = this.spacesRepository.findOne(spaceId);
			
			if(space == null) {
				throw new HttpClientErrorException(HttpStatus.NOT_FOUND, "space " + spaceId + " not found");
			}
			
			SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
			rand.setSeed(System.currentTimeMillis());
			byte[] rawSalt = new byte[50];
			rand.nextBytes(rawSalt);
			String newSalt = Hex.encodeHexString(rawSalt);
						
			
			model.addAttribute("spaceObj", space);
			model.addAttribute("salt", newSalt);
			model.addAttribute("key", space.getKey(newSalt));
						
			return "admin/spaceDeleteConfirm";
		}
		else if (RequestMethod.POST.equals(method) && key != null && !key.isEmpty() && salt != null && !salt.isEmpty()) {
						
			if(spaceId != null && spaceId.length() > 0) {
				
				Space space = this.spacesRepository.findOne(spaceId);
				if(space != null) {
					if(space.checkKey(key, salt)) {
						this.spacesRepository.delete(spaceId);
					}
					else {
						throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Key not ckecked");
					}
				}
				
			}
			return "redirect:/admin/spaces";
			
		}
		else {
			throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Bad request method or parameters"); 
		}
		
	}
	
}
