package managedbean.profile;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import javax.resource.NotSupportedException;
import javax.validation.constraints.Size;

import org.primefaces.PrimeFaces;

import TO.FamilyDoctorTO;
import TO.MedicalSpecialtyTO;
import TO.PatientTO;
import TO.PrimaryHealthCareCenterTO;
import TO.SpecialistDoctorTO;
import common.Constants;
import common.UserType;
import managedbean.common.ManagedBeanBase;
import managedbean.common.ValidationUtils;

/**
 * ManagedBEan que gestiona el registro de usuarios: Usuarios de tipo "Paciente"
 * Usuarios de tipo "Médico de Familia" usuarios de tipo "Médico especialista"
 * 
 * @author Marcos García Núñez (mgarcianun@uoc.edu)
 *
 */
@Named("RegisterUser")
@ViewScoped
public class RegisterUserMBean extends ManagedBeanBase implements Serializable {

	private static final long serialVersionUID = 1L;
	private int id;
	private String cipCode;
	private String nif;
	private String name;
	private String surname;
	@Size(min = 4, message = "La contraseña debe tener al menos 4 carácteres.")
	private String password;
	private String email;
	private boolean registered;
	private String lastUIQueryPH;
	private String lastUIQueryMS;

	// private HashMap<String, String> userTypes;
	private List<UserType> availableUserTypes;
	private UserType userType;
	private PrimaryHealthCareCenterTO primaryHealthCareCenter;
	private MedicalSpecialtyTO medicalSpecialty;
	private List<MedicalSpecialtyTO> medicalSpecialitiesList;
	private List<PrimaryHealthCareCenterTO> primaryHealthCareCentersList;

	public RegisterUserMBean() {

	}

	@PostConstruct
	public void init() {
		this.availableUserTypes = new ArrayList<UserType>();
		this.availableUserTypes.add(UserType.PATIENT);
		this.availableUserTypes.add(UserType.FAMILY_DOCTOR);
		this.availableUserTypes.add(UserType.SPECIALIST_DOCTOR);
		this.registered = false;
		this.lastUIQueryPH = "";
		this.lastUIQueryMS = "";

		this.userType = UserType.PATIENT;

		this.medicalSpecialitiesList = this.getRemoteManagerCommon().listMedicalSpecialitiesPaged(0, Constants.MAX_ITEMS_AUTOCOMPLETE_SEARCH);
		this.primaryHealthCareCentersList = this.getRemoteManagerCommon().listCAPsPaged(0, Constants.MAX_ITEMS_AUTOCOMPLETE_SEARCH);
	}

	public List<UserType> getAvailableUserTypes() {
		return availableUserTypes;
	}

	public void onUserTypeChange() {
		switch (this.userType) {
		case SPECIALIST_DOCTOR:
			try {
				PrimeFaces.current().ajax().addCallbackParam("specs", true);
			} catch (Exception e) {
				this.manageException(e);
			}
			break;
		case FAMILY_DOCTOR:
			try {
				PrimeFaces.current().ajax().addCallbackParam("caps", true);
			} catch (Exception e) {
				this.manageException(e);
			}
			break;
		case ADMINISTRATOR:
		case PATIENT:
			PrimeFaces.current().ajax().addCallbackParam("pats", true);
			break;
		}
	}

	public List<MedicalSpecialtyTO> getMedicalSpecialtiesList() {
		return medicalSpecialitiesList;
	}

	public List<PrimaryHealthCareCenterTO> getPhcList() {
		return primaryHealthCareCentersList;
	}

	public List<PrimaryHealthCareCenterTO> completePrimaryHealCareCenter(String query) {
		if (query != null && query.equals(this.lastUIQueryPH) == false) {
			this.lastUIQueryPH = query;
			// Recuperamos las 200 primeras coincidencias
			this.primaryHealthCareCentersList = this.getRemoteManagerCommon().listCAPsFiltered(query, 0, Constants.MAX_ITEMS_AUTOCOMPLETE_SEARCH);
		}
		return this.primaryHealthCareCentersList;
	}

	public List<MedicalSpecialtyTO> completeMedicalSpecialty(String query) {
		if (query != null && query.equals(this.lastUIQueryMS) == false) {
			this.lastUIQueryMS = query;
			// Recuperamos las 200 primeras coincidencias
			this.medicalSpecialitiesList = this.getRemoteManagerCommon().listMedicalSpecialitiesFiltered(query, 0, Constants.MAX_ITEMS_AUTOCOMPLETE_SEARCH);
		}
		return this.medicalSpecialitiesList;
	}
	
	public void hadleNIFValueChange() {
		boolean isDupe = false;
		if (ValidationUtils.checkIfNifAlreadyRegistered(this.getRemoteManagerCommon(), this.userType, this.nif, null) == true) {
			isDupe = true;	
			this.addFacesMessage("frmRegisterUser:nif", FacesMessage.SEVERITY_WARN, "NIF duplicado", "El nif indicado pertenece a otro usuario previamente registrado");
		}
		
		PrimeFaces.current().ajax().addCallbackParam("NIFisDupe", isDupe);
	}

	public boolean isPatient() {
		return (this.userType == UserType.PATIENT);
	}

	public boolean isFamilyDoctor() {
		return (this.userType == UserType.FAMILY_DOCTOR);
	}

	public boolean isSpecialistDoctor() {
		return (this.userType == UserType.SPECIALIST_DOCTOR);
	}

	public boolean isDoctor() {
		return (isFamilyDoctor() || isSpecialistDoctor());
	}

	public String getEmail() {
		return email;
	}

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

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getSurname() {
		return surname;
	}

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

	public String getName() {
		return name;
	}

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

	public String getNif() {
		return nif;
	}

	public void setNif(String nif) {
		this.nif = nif;
	}

	public void addNewUser() {
		int error = 0;

		if (this.isFamilyDoctor() && this.primaryHealthCareCenter == null) {
			this.addFacesMessage("frmRegisterUser:selPHC", FacesMessage.SEVERITY_WARN, "Centro de atención primaria no seleccionado", "Por favor, especifique un centro de atención primaria.");
			error++;
		}
		if (this.isSpecialistDoctor() && this.medicalSpecialty == null) {
			this.addFacesMessage("frmRegisterUser:selMS", FacesMessage.SEVERITY_WARN, "Especialidad médica no seleccionada", "Por favor, especifique una especialidad médica.");
			error++;
		}
		if (ValidationUtils.isValid(nif) == false) {
			this.addFacesMessage(FacesMessage.SEVERITY_WARN, "El NIF indicado no es válido", "Por favor, especifique un NIF válido.");
			error++;
		}
		if (ValidationUtils.checkIfNifAlreadyRegistered(this.getRemoteManagerCommon(), this.userType, this.nif, null) == true) {
			this.addFacesMessage("frmRegisterUser:nif", FacesMessage.SEVERITY_WARN, "NIF duplicado", "El nif indicado pertenece a otro usuario previamente registrado");
			error++;
		}

		if (error == 0) {
			try {
				switch (this.userType) {
				case PATIENT:
					PatientTO pat = this.getRemoteManagerProfile().registerPatient(id, nif, name, surname, password, email);
					this.cipCode = pat.getPersonalIdentificationCode();

					break;
				case FAMILY_DOCTOR:
					FamilyDoctorTO fd = this.getRemoteManagerProfile().registerFamilyDoctor(id, nif, name, surname, password, email, this.primaryHealthCareCenter);
					this.cipCode = fd.getProfessionalNumber();

					break;
				case SPECIALIST_DOCTOR:
					SpecialistDoctorTO sd = this.getRemoteManagerProfile().registerSpecialistDoctor(id, nif, name, surname, password, email, this.medicalSpecialty);
					this.cipCode = sd.getProfessionalNumber();

					break;
				case ADMINISTRATOR:
					throw new NotSupportedException("No se soporta el registro directo de administradores.");
				}

				this.registered = true;
				this.addFacesMessage(FacesMessage.SEVERITY_INFO, "Registro realizado", "El usuario " + name + " " + surname + " se ha registrado correctamente.");

			} catch (Exception e) {
				this.manageException(e);
			}
		}
	}

	public UserType getUserType() {
		return userType;
	}

	public void setUserType(UserType value) {
		this.userType = value;
	}

	public MedicalSpecialtyTO getMedicalSpecialty() {
		return medicalSpecialty;
	}

	public void setMedicalSpecialty(MedicalSpecialtyTO value) {
		this.medicalSpecialty = value;
	}

	public PrimaryHealthCareCenterTO getPrimaryHealthCareCenter() {
		return primaryHealthCareCenter;
	}

	public void setPrimaryHealthCareCenter(PrimaryHealthCareCenterTO value) {
		this.primaryHealthCareCenter = value;
	}

	public boolean isRegistered() {
		return registered;
	}

	public String getCipCode() {
		return cipCode;
	}

	public void setCipCode(String cipCode) {
		this.cipCode = cipCode;
	}

}
