package it.enea.cruise.model.user;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.*;

import it.enea.scp.idp.sdk.model.UserDto;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity(name = "user")
@Table(name = "Users")
@Access(AccessType.FIELD)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userid")
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long userid;

	private String subject;

	@Column(name = "email")
	private String email;

	@Column(name = "username")
	private String username;

	@Column(name = "userfirstname")
	private String name;

	@Column(name = "usersurname")
	private String surname;

	@Column(name = "address")
	private String address;

	@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, 
			mappedBy = "user", fetch = FetchType.LAZY)
	@Access(AccessType.PROPERTY)
	@JsonIgnoreProperties("user")
	private List<UserCommunity> usercommunities;

	@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, 
			mappedBy = "user", fetch = FetchType.LAZY)
	@Access(AccessType.PROPERTY)
	private List<UserRole> userroles;

	@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, 
			mappedBy = "user", fetch = FetchType.LAZY)
	@Fetch(FetchMode.JOIN) 
	private List<Device> devices;

	@Transient
	@JsonIgnore
	private List<Role> roles;

	@Transient
	@JsonIgnore
	private ArrayList<Community> communities;



	@Transient
	private String phone;

	@Transient
	private String organization;

	@Transient
	private UserToken token;


	
	private Boolean active;

	public void setSingleUsercommunity(UserCommunity uc) {
		if (this.usercommunities == null)
			this.usercommunities = new ArrayList<UserCommunity>();
		this.usercommunities.add(uc);
	}

	public void setSingleUserRole(UserRole ur) {
		if (this.userroles == null)
			this.userroles = new ArrayList<UserRole>();
		this.userroles.add(ur);
	}
	
	@Deprecated
	@JsonIgnore
	public String getTmpWallet() {
		return "òdkhògadhòh";
	}

	@Deprecated
	@JsonIgnore
	public Long getTmpCommunity() {
		return new Long(4);
	}

	@Deprecated
	@JsonIgnore
	public List<String> getKeycloakRoles() {
		List<String> ls = new ArrayList<String>();
		ls.add("registered");
		return ls;
	}

	@Deprecated
	public void addRole(Role role) {

	}

	@Deprecated
	public void setTmpWallet(String wallet) {

	}

	@Deprecated
	public void setTmpCommunity(Long community) {

	}

	@Deprecated
	public void setKeycloakRoles(List<String> kRoles) {

	}

	@JsonIgnore
	public String getEmail() {
		return this.email;
	}

	public void addUserRole(UserRole ur) {
		if (this.userroles == null)
			this.userroles = new ArrayList<UserRole>();
		this.userroles.add(ur);
	}

	public boolean hasRole(String roleName, Long communityId) {
		return true;
	}

	public boolean hasRole(String roleName) {
		Boolean result = false;
		for (Role r : roles) {
			if (r.getRolename().equals(roleName))
				return true;
		}
		return result;
	}

	public void setUserroles(List<UserRole> ur) {
		this.userroles = ur;
		if (this.roles == null)
			this.roles = new ArrayList<Role>();
		for (UserRole tmpUr : ur)
			this.roles.add(tmpUr.getRole());

	}

	public List<UserRole> getUserroles() {
		return this.userroles;

	}

	public List<UserCommunity> getUsercommunities() {
		return usercommunities;
	}

	public void setUsercommunities(List<UserCommunity> usercommunities) {

		this.usercommunities = usercommunities;
		if (this.communities == null)
			this.communities = new ArrayList<Community>();
		for (UserCommunity tmpUc : usercommunities)
			this.communities.add(tmpUc.getCommunity());
	}

	public List<Device> getDevices() {
		return devices;
	}
	
	public void setDevices(List<Device> devices) {
		this.devices = devices;
	}
	
	public User merge(User userTemp) {
		this.name = userTemp.getName();
		this.surname = userTemp.getSurname();
		this.organization = userTemp.getOrganization();
		this.address = userTemp.getAddress();
		this.phone = userTemp.getPhone();
		this.email = userTemp.getEmail();
		this.token = userTemp.getToken();
		return this;
	}

	public void addUserRoleInCommunity(Role r, Community c) {
		if (this.userroles == null)
			this.userroles = new ArrayList<UserRole>();
		UserRole ur = new UserRole();
		ur.setUser(this);
		ur.setRole(r);
		ur.setCommunity(c);
		this.userroles.add(ur);
	}

	public void dismissCommunities() {
		this.usercommunities.forEach(child -> child.dismissUser());
		this.usercommunities.forEach(child -> dismissUsercommunity(child));// SYNCHRONIZING THE OTHER SIDE OF
																			// RELATIONSHIP
		this.usercommunities.clear();
	}
	
	public void dismissUserRole() {
		//this.userroles.forEach(child -> child.dismissUser());
		this.userroles.forEach(child -> dismissUsesRole(child));// SYNCHRONIZING THE OTHER SIDE OF
																			// RELATIONSHIP
		this.usercommunities.clear();
	}

	public void dismissUsesRole(UserRole ur) {
		this.userroles.remove(ur);
	}
	
	public void dismissUsercommunity(UserCommunity uc) {
		this.usercommunities.remove(uc);
	}

	public void mergeWithDto(UserDto userdto) {
		this.name = userdto.getName();
		this.surname = userdto.getSurname();
		this.organization = userdto.getOrganization();
		this.address = userdto.getAddress();
		this.phone = userdto.getPhone();
		this.email = userdto.getEmail();
		this.subject = userdto.getUuid();
	}
	
	public String getUuid() {
		return this.subject;
	}

	@PreRemove
	public void removeLinks() {
		/*
		 * Devo rimuovere i link agli oggetti user e community e scollegare anche
		 * dall'altro lato della relazione
		 */
		this.getUsercommunities().removeAll(this.usercommunities);
		this.getUserroles().removeAll(userroles);
		this.getDevices().removeAll(devices);

	}
	
}
