package ejb.systemAdmin;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import TO.FamilyDoctorTO;
import TO.LoggedUserTO;
import TO.MedicalSpecialtyTO;
import TO.PatientTO;
import TO.SpecialistDoctorTO;
import common.Constants;
import common.HashUtils;
import common.UserType;
import ejb.common.CommonFacadeLocal;
import jpa.AdministratorJPA;
import jpa.MedicalSpecialtyJPA;

/**
 * 
 * @author Marcos García Núñez (mgarcianun@uoc.edu)
 *
 */
@Stateless
public class SystemAdminFacadeBean implements SystemAdminFacadeRemote {

	// Persistence Unit Context
	@PersistenceContext(unitName = "MyHealth")
	private EntityManager entman;

	@EJB
	CommonFacadeLocal commonServices;

	/**
	 * Si la autenticación no es correcgta devuelve null, sino devuelve un POJO con
	 * datos del usuario logeado.
	 * 
	 * La autenticación se realiza en 2 pasos:
	 * 
	 * Paso 1. Se intenta localizar un registro de usuario, por orden:
	 * 
	 * a. Primero Paciente, si el identificador comienza por los caracteres
	 * correctos.
	 * 
	 * b.Después médico de familia, si el identificador es de profesional
	 * 
	 * c. Si no lo localizamos buscamos el identificador en la tabla de médicos
	 * especialistas (el identificador es de profesional)
	 * 
	 * d. Si no hemos localizado aún al usuario, lo buscamos en la tabla de
	 * administradores, aún cuando el identificador comience por cualquier carácter
	 * (podría ser una dirección de email que comienza por caracteres del
	 * identificaodr de paciente o profesional)
	 * 
	 * Paso 2. Si hemos localizado un registro de usuario, verificamos si el
	 * password recibido coincide con el de la base de datos, en tal caso la
	 * autenticación se compelta y es correcta.
	 */
	public LoggedUserTO login(String userCode, String pwd) {
		LoggedUserTO usr = null;

		if (userCode.startsWith(Constants.PERSONAL_IDENTIFICATION_CODE_PREFIX)) {
			// Si el identificador de usuario es de tipo paciente, intentamos realizar el
			// login.
			PatientTO pat = this.commonServices.findPatientByCode(userCode);
			if (pat != null) {
				usr = new LoggedUserTO(String.valueOf(pat.getId()), pat.getName(), pat.getPassword(), UserType.PATIENT);
			}
		} else if (userCode.startsWith(Constants.PROFESSIONAL_NUMBER_PREFIX)) {
			// Si el identificador de usuario es de tipo profesional, intentamos realizar el
			// login, primero como médico de familia, después como especialista
			FamilyDoctorTO fd = this.commonServices.findFamilyDoctorByCode(userCode);

			if (fd != null) {
				usr = new LoggedUserTO(String.valueOf(fd.getId()), fd.getName(), fd.getPassword(), UserType.FAMILY_DOCTOR);
			} else {
				// No era un código de médico de familia, intenamos logearlo como especialista
				SpecialistDoctorTO sd = this.commonServices.findSpecialistDoctorByCode(userCode);

				if (sd != null) {
					usr = new LoggedUserTO(String.valueOf(sd.getId()), sd.getName(), sd.getPassword(), UserType.SPECIALIST_DOCTOR);
				}
			}
		}

		// Si todavía no hemos conseguido autenticar al usuario, podría tratarse de una
		// dirección de email de un administrador que empiece por
		// PERSONAL_IDENTIFICATION_CODE_PREFIX o por PROFESSIONAL_NUMBER_PREFIX, por lo
		// cual intentamos login contra la tabla de administradores
		if (usr == null) {
			// Intentamos recuperar un registro de administrador
			AdministratorJPA adm = entman.find(AdministratorJPA.class, userCode);

			if (adm != null) {
				usr = new LoggedUserTO(adm.getEmail(), adm.getEmail(), adm.getPassword(), UserType.ADMINISTRATOR);
			}
		}

		// Si el objeto usr, es que hemos localizado un registro de usuario, verificamos
		// la contraseña.
		if (usr != null) {
			// Comprobamos el password
			if (usr.getPassword().equals(HashUtils.hashMD5(pwd)) == false) {
				// Bad Password, devolvemos null! La autenticación falla.
				usr = null;
			}
		}

		return usr;
	}

	@Override
	public MedicalSpecialtyTO updateSpecialtyData(int id, String name, String description) throws Exception {
		MedicalSpecialtyJPA ms = entman.find(MedicalSpecialtyJPA.class, id);

		if (ms == null) {
			throw new Exception("No se pueden actualizar los datos de la especialidad porque no se encuentra en la base de datos ningún registro con id: " + String.valueOf(id));
		}

		ms.setName(name);
		ms.setDescription(description);

		entman.persist(ms);

		return this.commonServices.getPOJOforMedicalSpecialtyJPA(ms);
	}
	
	@Override
	public void deleteSpecialtyData(int id, String name, String description) throws Exception {
		MedicalSpecialtyJPA ms = entman.find(MedicalSpecialtyJPA.class, id);

		if (ms == null) {
			throw new Exception("No se puede borrar la especialidad porque no se encuentra en la base de datos ningún registro con id: " + String.valueOf(id));
		}

		entman.remove(ms);
	}

	@Override
	public MedicalSpecialtyTO insertSpecialtyData(String name, String description) throws Exception {

		MedicalSpecialtyJPA ms = new MedicalSpecialtyJPA(name, description);
		entman.persist(ms);

		return this.commonServices.getPOJOforMedicalSpecialtyJPA(ms);
	}
}
