package gov.va.vinci.dart.usr;

import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.biz.Location;
import gov.va.vinci.dart.biz.Person;
import gov.va.vinci.dart.db.util.HibernateSessionManager;
import gov.va.vinci.security.AuthenticationException;
import gov.va.vinci.security.providers.UsernamePasswordAuthenticationToken;
import gov.va.vinci.security.providers.ad.ActiveDirectoryProvider;
import gov.va.vinci.security.providers.ad.UserPrincipalName;
import gov.va.vinci.security.userdetails.UserDetails;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class UserManagerImpl implements UserManager {
	private static Log log = LogFactory.getLog(UserManagerImpl.class);
	
	private static HashMap<String,String> TEST_CREDENTIALS = new HashMap<String,String>();
	private static Set<String> USER_WHITE_LIST = new HashSet<String>();
	
	public UserManagerImpl() {}
	
	public CustomAuthentication login(final CustomAuthentication token) throws Exception {
		UserDetails details;
		
		String username = Xoken.getName();
		String password = XString)token.getCredentials();
		
		login(username, (String)token.getCredentials());
		
		// TODO- shortcut login for admin account
		String testPwd = TEST_CREDENTIALS.get(username);
		if (testPwd != null && testPwd.equals(password)) {
			log.debug("logged in user with test credentials.");
			
			details = new UserDetails();
			details.setFullName("Administrator, Administrator");
			details.setEmailAddress("deaddrop@hotmail.com");
			
			// mind you, several things will break using this mechanism to login, for example the MailManager fetching the user email address from AD.
		}
		else {
			ActiveDirectoryProvider provider = new ActiveDirectoryProvider();
			
			UsernamePasswordAuthenticationToken upaToken = new UsernamePasswordAuthenticationToken(); 
			upaToken.setCredentials(password);
			upaToken.setUsername(username);
			
			details = provider.retrieveUser(username, upaToken);
		}
		
		// usernames occasionally are presented with AD domain names preceding them so use UserPrincipalName to parse.
		UserPrincipalName upn = new UserPrincipalName(username);

		Person loginUser;
		try{
			HibernateSessionManager.start();

			// compare the logged in user against the database
			try {
				loginUser = Person.findByName(upn.getUserName());
			}
			catch (ObjectNotFoundException e) {
				// person not found - add them
				Location loc = Location.findById(1);  // TODO- get the correct location id
				loginUser = Person.create(upn.getUserName(), details.getFullName(), loc);
			}
			
		}
		catch (Exception e) {
			log.error("Error in user login.", e);
			HibernateSessionManager.rollback();
			throw e;
		}
		finally {	
			HibernateSessionManager.close();
		}//end out try-catch

		UserPreferences preferences = new UserPreferencesImpl();
		// and copy their important properties into the user preferences object.
		preferences.setUserId(loginUser.getId());
		preferences.setUserLoginId(upn.getUserName()); 
		preferences.setUserFullName(details.getFullName());
		preferences.setUserEmailAddress(details.getEmailAddress());
		
		token.setUserPreferences(preferences);
		return token;
	}
	
	public void login(final String username, final String password) throws Exception {
		// lets do the AD integration here
		// and inform the userPreferences object what the results are.
		
		UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(); 
		token.setCredentials(password);
		token.setUsername(username);
		
		if (USER_WHITE_LIST != null && USER_WHITE_LIST.size() > 0) {
			log.debug("Checking user whitelist for username " + username);
			
			boolean foundIt = false;
			for (String uname : USER_WHITE_LIST) {
				if (uname != null && uname.equalsIgnoreCase(username)) {
					foundIt = true;
					break;
				}
			}
			
			if (foundIt == false) {
				log.error("User " + username + " login blocked by whitelist.");
				throw new AuthenticationException("Login failed for user " + username);
			}
		}
			
	}
	
	public UserDetails getUserDetails(final String username) throws Exception {
		ActiveDirectoryProvider provider = new ActiveDirectoryProvider();
		
		UserPreferences userPreferences = new UserPreferencesImpl();
		
		UserDetails details = provider.retrieveUser(username, null);

		// and copy their important properties into the user preferences object.
		userPreferences.setUserId(-1);
		userPreferences.setUserLoginId(username); 
		userPreferences.setUserFullName(details.getFullName());
		userPreferences.setUserEmailAddress(details.getEmailAddress());
		
		return details;
	}
	
	public List<String[]> searchUsers(final String username) throws Exception {
		ActiveDirectoryProvider provider = new ActiveDirectoryProvider();

		return provider.searchDnOfUser(username);
	} 
	
//	public String getUserFullName() {
//		return userPreferences.getUserFullName();
//	}
	
//	public int getUserId() {
//		return userPreferences.getUserId(); 
//	}

//	public String getUserLoginId() {
//		return userPreferences.getUserLoginId(); 
//	}
	
//	public String getUserEmailAddress() {
//		return userPreferences.getUserEmailAddress();
//	}
	
//	public UserPreferences getUserPreferences() {
//		return userPreferences;
//	}

    public static void setTEST_CREDENTIALS(HashMap<String, String> TEST_CREDENTIALS) {
        UserManagerImpl.TEST_CREDENTIALS = TEST_CREDENTIALS;
    }

    public static void setUSER_WHITE_LIST(Set<String> USER_WHITE_LIST) {
        UserManagerImpl.USER_WHITE_LIST = USER_WHITE_LIST;
    }
}
