package models;

import java.util.Date;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Transient;

import net.eclettica.esecure.models.EsAccount;

import net.eclettica.esecure.models.EsRole;
import net.eclettica.esecure.services.AuthService;
import play.Logger;
import utils.StringUtil;

/**
 * A representation of the model object User
 * 
 */

@Entity(name = "EndUser")
public class User extends ModelUuid implements EsAccount {

	// public static enum Roles {
	// ADMIN, CONTENT_PROVIDER, USER;
	//
	// public static Roles tryBuildUserRoleFromValue(String val) {
	// if (StringUtil.isNil(val)) {
	// return null;
	// }
	//
	// for (Roles userRole : values()) {
	// if (userRole.name().equals(val)) {
	// return userRole;
	// }
	// }
	//
	// return null;
	// }
	// }

	// public static enum Authorizations {
	// TEST_MANAGEMENT, MEDIA_MANAGEMENT, USER_MANAGEMENT, REPORT_MANAGEMENT;
	//
	// public static Authorizations tryBuildUserRoleFromValue(String val) {
	// if (StringUtil.isNil(val)) {
	// return null;
	// }
	//
	// for (Authorizations authorization : values()) {
	// if (authorization.name().equals(val)) {
	// return authorization;
	// }
	// }
	//
	// return null;
	// }
	// }

	public static class Authorizations {
		public static final String TEST_MANAGEMENT = "TEST_MANAGEMENT";
		public static final String MEDIA_MANAGEMENT = "MEDIA_MANAGEMENT";
		public static final String USER_MANAGEMENT = "USER_MANAGEMENT";
		public static final String REPORT_MANAGEMENT = "REPORT_MANAGEMENT";

		public static List<String> values() {
			List<String> ret = new LinkedList<String>();
			ret.add(MEDIA_MANAGEMENT);
			ret.add(REPORT_MANAGEMENT);
			ret.add(USER_MANAGEMENT);
			ret.add(TEST_MANAGEMENT);
			for (String auth : AuthService.instance().ES_AUTHS) {
				ret.add(auth);
			}
			return ret;
		}

		public static boolean checkAuthorization(String val) {
			if (StringUtil.isNil(val)) {
				return false;
			}

			for (String authorization : values()) {
				if (StringUtil.isNil(authorization)) {
					continue;
				}
				if (authorization.equals(val)) {
					return true;
				}
			}

			return false;
		}
	}

	public static class Roles {
		public static final String ROLE_SEPARATOR = " ";
		public static final String ADMIN = "ADMIN";
		public static final String CONTENT_PROVIDER = "CON_PRO";
		public static final String USER = "USER";

		public static List<String> values() {
			List<String> ret = new LinkedList<String>();
			ret.add(ADMIN);
			ret.add(CONTENT_PROVIDER);
			ret.add(USER);
			return ret;
		}

		public static boolean checkRole(String val) {
			if (StringUtil.isNil(val)) {
				return false;
			}

			for (String role : values()) {
				if (StringUtil.isNil(role)) {
					continue;
				}
				if (role.equals(val)) {
					return true;
				}
			}

			return false;
		}
	}

	@Basic(optional = false)
	private String esAccountId;

	@Transient
	public static final String REGISTRATION_DATE_FORMAT = "dd/MM/yyyy";
	private Date registrationDate;

	private String name;

	private String surname;

	private String email;

	private Boolean deleted = false;

	private String verificationCode;

	public User(String username) {
		this.email = username;
	}

	public User() {
		super();
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getRegistrationDate() {
		return registrationDate;
	}

	public void setRegistrationDate(Date registrationDate) {
		this.registrationDate = registrationDate;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSurname() {
		return surname;
	}

	public void setSurname(String surname) {
		this.surname = surname;
	}

	public Boolean isDeleted() {
		return deleted;
	}

	public void setDeleted(Boolean deleted) {
		this.deleted = deleted;
	}

	public String getVerificationCode() {
		return verificationCode;
	}

	public void setVerificationCode(String verificationCode) {
		this.verificationCode = verificationCode;
	}

	public Boolean getDeleted() {
		return deleted;
	}

	public String getEsAccountId() {
		return esAccountId;
	}

	public void setEsAccountId(String esAccountId) {
		this.esAccountId = esAccountId;
	}

	public void setEsAccountId(models.eSecurePlay1.EsAccount esAccount) {
		this.esAccountId = esAccount.getUuid();
	}

	@Override
	public String getUserGroup() {
		models.eSecurePlay1.EsAccount acc = models.eSecurePlay1.EsAccount.findById(esAccountId);
		if (acc != null)
			return acc.getUserGroup();
		else
			return null;
	}

	@Override
	public String getUsername() {
		models.eSecurePlay1.EsAccount acc = models.eSecurePlay1.EsAccount.findById(esAccountId);
		if (acc != null)
			return acc.getUsername();
		else
			return null;
	}

	@Override
	public String getPassword() {
		models.eSecurePlay1.EsAccount acc = models.eSecurePlay1.EsAccount.findById(esAccountId);
		if (acc != null)
			return acc.getPassword();
		else
			return null;
	}

	public static User findByEsAccountId(String esAccountId) {
		return User.find("esAccountId=:esAccountId").setParameter("esAccountId", esAccountId).first();
	}

	public String buildUserJsonFieldRole() {
		List<EsRole> roles = retrieveUserRoles();
		String ret = "";
		String sep = "";
		for (EsRole role : roles) {
			ret += sep + role.getName();
			sep = Roles.ROLE_SEPARATOR;
		}

		return ret;
	}

	public String[] buildUserStringArrayRole() {
		String[] ret = {};
		List<EsRole> roles = retrieveUserRoles();
		String temp = "";
		String sep = "";
		for (EsRole role : roles) {
			temp += sep + role.getName();
			sep = Roles.ROLE_SEPARATOR;
		}

		if (temp.length() > 0) {
			try {
				ret = temp.split(Roles.ROLE_SEPARATOR);
			} catch (Exception ex) {
				Logger.error(ex, "Exception while splitting roles");
			}
		}
		return ret;
	}

	private List<EsRole> retrieveUserRoles() {
		List<EsRole> roles = AuthService.instance().findRoleByUser(this.esAccountId);
		if (roles == null) {
			roles = new LinkedList<EsRole>();
		}
		return roles;
	}
	
	public String getRole() {
		models.eSecurePlay1.EsAccount acc = models.eSecurePlay1.EsAccount.findById(esAccountId);
		Set<models.eSecurePlay1.EsRole> roles = acc.getRoles();
		Iterator<models.eSecurePlay1.EsRole> it = roles.iterator();
		String ret = "";
		String sep = "";
		while(it.hasNext()){
			ret += sep + it.next().getName();
			sep = " ";
		}
		return ret;
	}

	public static class UserRoles {
		public boolean hasAdminRole = false;
		public boolean hasContentProviderRole = false;
		public boolean hasUserRole = false;
	}

	public UserRoles retrieveRoles() {
		UserRoles userRoles = new UserRoles();
		List<EsRole> roles = retrieveUserRoles();
		if (roles != null && !roles.isEmpty()) {
			for (EsRole role : roles) {
				if (role.getName().equals(Roles.ADMIN)) {
					userRoles.hasAdminRole = true;
				} else if (role.getName().equals(Roles.CONTENT_PROVIDER)) {
					userRoles.hasContentProviderRole = true;
				} else if (role.getName().equals(Roles.USER)) {
					userRoles.hasUserRole = true;
				}
			}
		}
		return userRoles;
	}

	public static List<User> findAllFilteredByRoleAndEmailAndName(String role, String email, String name) {
		List<User> ret = new LinkedList<User>();

		boolean filtered = false;
		String query = "";
		String sep = "";
		Map<String, Object> queryParams = new LinkedHashMap<String, Object>();
		if (!StringUtil.isNil(email)) {
			filtered = true;
			query += sep + "email LIKE :email";
			sep = " AND ";
			queryParams.put("email", "%" + email + "%");
		}
		if (!StringUtil.isNil(name)) {
			filtered = true;
			query += sep + "name LIKE :name";
			sep = " AND ";
			queryParams.put("name", "%" + name + "%");
		}

		if (filtered) {
			JPAQuery q = User.find(query);
			for (String key : queryParams.keySet()) {
				q.setParameter(key, queryParams.get(key));
			}
			ret = q.fetch();
		}

		if (!StringUtil.isNil(role)) {
			List<User> filteredByRoles = new LinkedList<User>();
			List<User> list;

			if (filtered) {
				list = ret;
			} else {
				list = User.findAll();
			}

			filtered = true;

			for (User u : list) {
				String[] roles = u.buildUserStringArrayRole();
				if (roles == null || roles.length <= 0) {
					continue;
				}
				for (String esRole : roles) {
					if (esRole.equals(role)) {
						filteredByRoles.add(u);
						break;
					}
				}
			}

			ret = filteredByRoles;
		}

		if (!filtered) {
			ret = User.findAll();
			return ret;
		}

		return ret;
	}

	public static List<User> findAllByDeleted(Boolean deleted) {
		List<User> ret = new LinkedList<User>();
		if (deleted == null) {
			ret = User.findAll();
		} else {
			ret = User.find("deleted=:deleted").setParameter("deleted", deleted).fetch();
		}
		return ret;
	}

	public static User findByUsername(String username) {
		User u = find("email = :username").setParameter("username", username).first();
		return u;
	}

	public String buildFullName() {
		String fullName = "";
		if (!StringUtil.isNil(this.name)) {
			fullName += this.name + " ";
		}
		if (!StringUtil.isNil(this.surname)) {
			fullName += this.surname;
		}
		return fullName;
	}
}