package org.minager.account;

import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

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

import org.minager.core.entities.dto.PasswordWrapperDTO;
import org.minager.core.entities.dto.UserDTO;
import org.minager.core.entities.persistence.User;
import org.minager.core.repositories.UserRepository;
import org.minager.core.security.TokenService;
import org.minager.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
public class AccountService {
	
	@Autowired
	private UserRepository userRepository;

	@Autowired
	private TokenService tokenService;
	
	/**
	 * Check the user credentials and generate him a token if they are correct.
	 * 
	 * @param pUser
	 *            The user sent from client.
	 * @return The user populated with the generated token.
	 * @throws IOException
	 *             If the credentials are bad.
	 * @throws AuthenticationException
	 *             If the credentials are wrong.
	 */
	public UserDTO checkCredentials(HttpServletResponse pResponse, UserDTO pUser) throws IOException {
		UserDTO result = null;
		
		Optional<User> user = userRepository.findByEmail(pUser.getEmail());
		
		if(user.isPresent() && StringUtils.compareHash(pUser.getPassword(), user.get().getPassword())) {
			tokenService.addUser(user.get());
			result = new UserDTO(user.get(), true);
		} else {
			pResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
		}
		
		return result;
	}
	
	public void changePassword(final User pUser, final PasswordWrapperDTO pPasswordWrapper,
			final HttpServletResponse pResponse) throws IOException {
		if(pPasswordWrapper.getNewPassword().equals(pPasswordWrapper.getConfirmPassword())) {
			// We fetch the connected user from database to get his hashed password
			final Optional<User> userFromDb = userRepository.findById(pUser.getId());
			if(userFromDb.isPresent() && StringUtils.compareHash(pPasswordWrapper.getOldPassword(),
					userFromDb.get().getPassword())) {
				userFromDb.get().setPassword(StringUtils.hashPassword(pPasswordWrapper.getNewPassword()));
				userRepository.save(userFromDb.get());
			} else {
				pResponse.sendError(HttpServletResponse.SC_FORBIDDEN,
						"Le mot de passe saisi ne correspond pas au votre.");
			}
		} else {
			pResponse.sendError(HttpServletResponse.SC_BAD_REQUEST,
					"Le mot de passe saisi ne correspond pas au votre.");
		}
	}
	
	public UserDTO signin(final UserDTO pUser, final HttpServletResponse pResponse) throws IOException {
		User user = new User();
		
		if(pUser.getName() == null || pUser.getEmail() == null || pUser.getPassword() == null || "".equals(pUser.getPassword().trim())) {
			pResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
		} else if(userRepository.findByEmail(pUser.getEmail()).isPresent()) {
			pResponse.sendError(HttpServletResponse.SC_CONFLICT);
		} else {
			user.setName(pUser.getName());
			user.setEmail(pUser.getEmail());
			user.setPassword(StringUtils.hashPassword(pUser.getPassword()));
			user.setInscriptionDate(new Date());
			userRepository.save(user);
		}
		
		return new UserDTO(user);
	}
	
	public void updateUser(final UserDTO pUser, final HttpServletRequest pRequest,
			final HttpServletResponse pResponse) throws IOException {
		final Optional<User> connectedUserOpt = tokenService.getAuthenticatedUserByToken(pRequest);
		if(connectedUserOpt.isPresent()) {
			final User connectedUser = connectedUserOpt.get();
			
			final Optional<User> userFromDb = userRepository.findByEmail(pUser.getEmail());
			
			/*
			 * If a user is returned by the repository, that's the email adress is used, but
			 * if it is not the same as the connected user, that's the email adress
			 * corresponds to another user. So a 409 error is sent. Otherwise, if no user is
			 * returned by the repository, that's the email adress is free to be used. So,
			 * user can change him email adress.
			 */
			if(userFromDb.isPresent() && !connectedUser.getEmail().equals(userFromDb.get().getEmail())) {
				pResponse.sendError(HttpServletResponse.SC_CONFLICT);
			} else {
				connectedUser.setName(pUser.getName());
				connectedUser.setEmail(pUser.getEmail());
				
				userRepository.save(connectedUser);
			}
		} else {
			pResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
		}
	}
}
