package ejb.medicalTest;

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

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

import TO.LoggedUserTO;
import TO.MedicalSpecialtyTO;
import TO.MedicalTestTO.MedicalTestType;
import TO.QuestionTO;
import common.QuestionStatus;
import common.UserType;
import ejb.common.CommonFacadeLocal;
import jpa.FamilyDoctorJPA;
import jpa.PatientJPA;
import jpa.QuestionJPA;
import managedbean.common.SessionUtils;

/**
 * EJB Session Bean Class para la Practica 2, Ejercicio 1 (ISCSD) Implementa los
 * métodos de la capa de negocio que implementan la logica de negocio y la
 * interacción con la capa de persistencia.
 * 
 * Tanto los pacientes como los médicos deben acceder a la vista de pruebas
 * médicas.
 * 
 * @author rorden
 *
 */
@Stateless
public class MedicalTestFacadeBean implements MedicalTestFacadeRemote {
	// Persistence Unit Context
	@PersistenceContext(unitName = "MyHealth")
	EntityManager entman;

	@EJB
	CommonFacadeLocal commonServices;

	// *********************************************************************
	// QUESTION_RESPONSE

	/**
	 * Realizar una pregunta al médico por un paciente
	 * 
	 * @param professionalNumber
	 * @param title
	 * @param message
	 */
	@Override
	public void askQuestion(int professionalNumber, String title, String message) {
		LoggedUserTO user = SessionUtils.getloggedOnUser();
		// 0. Conseguir el paciente en sesión
		PatientJPA patient = entman.find(PatientJPA.class, user.getId());
		// 1. Buscar el médico de familia con ese professionalNumber
		FamilyDoctorJPA fdoctor = entman.find(FamilyDoctorJPA.class, professionalNumber);
		// 2. Crear un objeto de Question para ese médico desde el paciente en sesión
		QuestionJPA question = new QuestionJPA(0, title, message, QuestionStatus.PENDING, patient, fdoctor, null);
		// 3. Guardar
		entman.persist(question);
	}

	/**
	 * El médico responde a una pregunta
	 * 
	 * @param question
	 * @param response
	 */
	@Override
	public void answerQuestion(QuestionTO q) {
		QuestionJPA qjpa;
		if(q.getId() >= 0) {
			qjpa = entman.find(QuestionJPA.class, q.getId());
			qjpa.setResponse(q.getResponse());
			qjpa.setStatus(QuestionStatus.ANSWERED);
		} else {
			qjpa = new QuestionJPA();
			qjpa.setId(0);
			qjpa.setTitle(q.getTitle());
			qjpa.setMessage(q.getMessage());
			qjpa.setStatus(QuestionStatus.PENDING);
		}
		
		PatientJPA pat = entman.find(PatientJPA.class, q.getPatient().getId());
		qjpa.setPatient(pat);
		qjpa.setFamilyDoctor(pat.getFamilyDoctor());

		entman.persist(qjpa);
	}

	@Override
	public List<QuestionTO> listAllPendingQuestions(int familyDoctorId) {
		// TypedQuery<QuestionJPA> query = entman.createQuery("SELECT q from QuestionJPA
		// q where q.status=:status and q.familyDoctor.id=:docId order by q.title",
		// QuestionJPA.class);
		TypedQuery<QuestionJPA> query = entman.createQuery(
				"SELECT q from QuestionJPA q where q.familyDoctor.id=:docId order by q.status desc, q.title asc",
				QuestionJPA.class);
		// query.setParameter("status", QuestionStatus.PENDING);
		query.setParameter("docId", familyDoctorId);

		List<QuestionJPA> allJPA = query.getResultList();
		List<QuestionTO> pendingQuestions = new ArrayList<QuestionTO>();

		for (QuestionJPA item : allJPA) {
			pendingQuestions.add(commonServices.getPOJOforQuestionJPA(item, 1));
		}

		return pendingQuestions;
	}

	public List<QuestionTO> listAllMyQuestions(int userId) {
		List<QuestionTO> pendingQuestions = new ArrayList<QuestionTO>();
		// TypedQuery<QuestionJPA> query = entman.createQuery("SELECT q from QuestionJPA
		// q where q.status=:status and q.familyDoctor.id=:docId order by q.title",
		// QuestionJPA.class);
		TypedQuery<QuestionJPA> query = entman.createQuery(
				"SELECT q from QuestionJPA q where q.patient.id=:patientId order by q.status desc, q.title asc",
				QuestionJPA.class);
		// query.setParameter("status", QuestionStatus.PENDING);
		query.setParameter("patientId", userId);

		List<QuestionJPA> allJPA = query.getResultList();

		for (QuestionJPA item : allJPA) {
			pendingQuestions.add(commonServices.getPOJOforQuestionJPA(item, 1));
		}

		return pendingQuestions;
	}

	public Long getPendingQuestionsCount(int familyDoctorId) {
		TypedQuery<Long> query = entman.createQuery(
				"SELECT count(1) from QuestionJPA q where q.status=:status and q.familyDoctor.id=:docId", Long.class);
		query.setParameter("status", QuestionStatus.PENDING);
		query.setParameter("docId", familyDoctorId);

		return query.getSingleResult();
	}

	public List<QuestionTO> listPendingQuestionsPaged(int familyDoctorId, int pageNumber, int pageSize) {
		TypedQuery<QuestionJPA> query = entman.createQuery(
				"SELECT q from QuestionJPA q where q.status=:status and q.familyDoctor.id=:docId order by q.title",
				QuestionJPA.class);
		query.setParameter("status", QuestionStatus.PENDING);
		query.setParameter("docId", familyDoctorId);

		if (pageSize > 0) {
			query.setFirstResult(pageNumber * pageSize);
			query.setMaxResults(pageSize);
		}

		List<QuestionJPA> allJPA = query.getResultList();
		List<QuestionTO> pendingQuestions = new ArrayList<QuestionTO>();

		for (QuestionJPA item : allJPA) {
			pendingQuestions.add(commonServices.getPOJOforQuestionJPA(item, 1));
		}

		return pendingQuestions;
	}

	/**
	 * Recuperar una pregunta por su String
	 * 
	 * @param question
	 */
	@Override
	public void getQuestion(String question) {
	}

	// *********************************************************************
	// MEDICAL_TEST

	/**
	 * Añadir pruebas médicas a una cita
	 * 
	 * Sólo médicos especialistas pueden gestionar pruebas médicas en el sistema.
	 * 
	 * @param idMedicalTest
	 * @param date
	 * @param time
	 * @param testType      Pudiera llegar a ser: Análisis de sangre, resonancias
	 *                      magnéticas y TAC
	 * @param observations
	 */
	@Override
	public void addMedicalTest(int idMedicalTest, Date date, long time, MedicalTestType testType, String observations) {
	}

	/**
	 * Recuperar una prueba médica por ID
	 * 
	 * Pueden ser consultas por médicos de familia
	 * 
	 * @param idMedicalTest
	 */
	@Override
	public void getMedicalTest(int idMedicalTest) {
	}

	/**
	 * Añadir una imagen a una prueba médica
	 * 
	 * @param idMedicalTest
	 * @param image
	 */
	@Override
	public void addImage(int idMedicalTest, String image) {
	}

	/**
	 * Actualizar/Pisar una imagen a una prueba médica
	 * 
	 * @param idMedicalTest
	 * @param image
	 */
	@Override
	public void updateImage(int idMedicalTest, String image) {
	}

	/**
	 * Eliminar una imagen a una prueba médica
	 * 
	 * @param idMedicalTest
	 */
	@Override
	public void removeImage(int idMedicalTest) {
	}

	/**
	 * Listar médicos con una especialidad concreta
	 * 
	 * @param speciality
	 */
	@Override
	public void findSpecialistDoctorByMedicalSpeciality(MedicalSpecialtyTO speciality) {
	}

}