package com.ejie.ad74a.ws.server.televida.service;

import java.util.HashMap;

import javax.jms.Message;
import javax.jms.ObjectMessage;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ejie.ad74a.constantes.Constantes;
import com.ejie.ad74a.exceptions.ManagerErrors;
import com.ejie.ad74a.jms.util.UtilJms;
import com.ejie.ad74a.model.ErroresTelevida;
import com.ejie.ad74a.model.Expedientes;
import com.ejie.ad74a.model.PeticionesPs;
import com.ejie.ad74a.model.Solicitantes;
import com.ejie.ad74a.scheduler.JobSchedulerService;
import com.ejie.ad74a.scheduler.SchedulerJobType;
import com.ejie.ad74a.service.ErroresTelevidaService;
import com.ejie.ad74a.service.PeticionesPsService;
import com.ejie.ad74a.util.comun.UtilidadesXML;
import com.ejie.ad74a.util.constantes.AccionesTelevidaEnum;
import com.ejie.ad74a.util.constantes.RespuestasTelevidaEnum;
import com.ejie.ad74a.ws.client.prestadorWS.service.PrestadorWSService;
import com.ejie.ad74a.ws.server.televida.model.Comunicacion;
import com.ejie.ad74a.ws.server.televida.model.Respuesta;
import com.ejie.ad74a.ws.server.televida.util.ModelApplicationParser;

@Service(value = "TelevidaService")
public class TelevidaServiceImpl implements TelevidaService {

	/**
	 * Final static logger.
	 */
	private static final Logger logger = LoggerFactory.getLogger(TelevidaServiceImpl.class);

	@Autowired
	private ErroresTelevidaService erroresTelevidaService;

	@Autowired
	private PeticionesPsService peticionesPsService;

	@Autowired
	private ValidacionesPrestador validacionesPrestador;

	@Autowired
	private ProcesarPrestador procesarPrestador;

	@Autowired
	private TelevidaProccesService televidaProccesService;

	@Autowired
	private PrestadorWSService prestadorWSService;

	@Autowired
	private JobSchedulerService jobSchedulerService;

	/**
	 * Validación inicial de la petición previa a añadirla a la cola de
	 * procesamiento
	 */
	@Override
	public Respuesta initialValidationComunication(Comunicacion comunicacion) throws Throwable {
		TelevidaServiceImpl.logger.info("TelevidaServiceImpl.proccesMessage - Inicio");
		Respuesta result = null;

		try {
			result = this.validacionesPrestador.validacionInicialCabecera(comunicacion);
			if (!RespuestasTelevidaEnum.EN_PROCESO.getCodRespuesta().equals(result.getCodRespuesta())) {
				return result;
			}

			/*
			 * Si pasa validación:
			 * 
			 * - añadir a tabla AD74A99T00
			 * 
			 * - enviar a la cola con el id devuelto
			 * 
			 * - crear respuesta de en procesamiento
			 * 
			 * Si no pasa validación:
			 * 
			 * - crear respuesta de error xsd y texto del error
			 */

			String accion = comunicacion.getCabecera().getTipoComunicacion().value();
			if (accion.equalsIgnoreCase(AccionesTelevidaEnum.ALTA.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialAltaInstalacion(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.UPDATE.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialUpdate(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.BAJA_BENEFICIARIO.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialBajaBeneficiario(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.BAJA_INSTALACION.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialBajaInstalacion(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.PRESTACION.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialPrestacion(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.QUEJAS_RECLAMACIONES.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialQuejas(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.VALORACION.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialValoracion(comunicacion);
			} else if (accion.equalsIgnoreCase(AccionesTelevidaEnum.CAMBIO_DOMICILIO.getLabelDesc())) {
				result = this.validacionesPrestador.validacionInicialCambioDomicilio(comunicacion);
			} else {
				result = RespuestasTelevidaEnum.ERROR_GENERICO.getRespuesta();
				ManagerErrors.manageError("Accion no existente - accion: " + accion);
			}

			// Si es valido, añadir a la BBDD y el id devuelto a la cola de procesamiento
			if (RespuestasTelevidaEnum.EN_PROCESO.getCodRespuesta().equals(result.getCodRespuesta())) {
				PeticionesPs peticionPs = new PeticionesPs();
				peticionPs.setCola99(PeticionesPs.COLA_PROCESAR);
				peticionPs.setIdPeticionOriginal99(comunicacion.getCabecera().getIdPeticion());
				peticionPs.setNumAbonado99(comunicacion.getCabecera().getNumAbonado());
				peticionPs.setMensaje99(UtilidadesXML.marshalObjectWS(comunicacion));
				peticionPs.setProcesado99(Constantes.CERO);
				peticionPs = this.peticionesPsService.add(peticionPs);

				// Añadir a la cola de procesamiento
				try {
					UtilJms.enviarJMS(peticionPs.getIdPeticion99(),
							com.ejie.ad74a.constantes.Constantes.CONNECTION_FACTORY_JNDI_NAME,
							com.ejie.ad74a.constantes.Constantes.PETICION_PRESTADOR_DESTINATION_JNDI_NAME, null, null);
				} catch (Exception e) {
					ExceptionUtils.getStackTrace(e);
				}

			}
		} catch (Exception e) {
			// e.printStackTrace();
			result = RespuestasTelevidaEnum.ERROR_GENERICO.getRespuesta();
			result.setMensaje(e.getMessage());
			ManagerErrors.manageError("Error al validar la petición: " + ExceptionUtils.getStackTrace(e));
		}

		result.setIdPeticion(comunicacion.getCabecera().getIdPeticion());
		return result;
	}

	/**
	 * Procesamiento de la petición desde la cola
	 */
	@Override
	public synchronized void proccesMessage(Message message) throws Throwable {

		Respuesta respuesta = RespuestasTelevidaEnum.ERROR_GENERICO.getRespuesta();
		// 1.- Obtener los datos del mensaje
		ObjectMessage msg = null;

		if (message instanceof ObjectMessage) {
			msg = (ObjectMessage) message;
			TelevidaServiceImpl.logger.debug("TelevidaServiceImpl - proccesMessage msg: " + msg);

//			// 2.- Obtener los datos de la bbdd a partir del id del mensaje (tabla
//			// AD74A99T00)
			PeticionesPs peticionPs = new PeticionesPs();
			peticionPs.setIdPeticion99((Long) msg.getObject());
			peticionPs = this.peticionesPsService.find(peticionPs);

			// String xml = UtilSQL.clobToString(peticionPs.getMensaje99());
			String xml = peticionPs.getMensaje99Str();
			Comunicacion comunicacion = (Comunicacion) UtilidadesXML.unmarshallerObject(xml, Comunicacion.class);

//			// 3.- Procesar la petición
			this.procesar(comunicacion, true);

			// 5.- Marcar la petición como procesada
			// Más adelante, en función del volumen habrá que ver si se borra
			this.peticionesPsService.updateProcesado(peticionPs);
		}

		// 6.- Marcar como procesada en la cola
		message.acknowledge();

		TelevidaServiceImpl.logger.info("TelevidaServiceImpl.proccesMessage - Fin");
		// return respuesta;

	}

	private void procesar(Comunicacion comunicacion, Boolean guardarError) throws Throwable {

		Respuesta respuesta = RespuestasTelevidaEnum.OK.getRespuesta();

		try {
			respuesta = this.procesarPrestador.proccesComunication(comunicacion);
		} catch (Exception e) {
			e.printStackTrace();
			// guardamos el mensaje de error si es necesario
			if (guardarError) {
				ErroresTelevida comunicationError = ModelApplicationParser.getComunicationToError(comunicacion);
				comunicationError.setErrormsg51(getErrorMessage(ExceptionUtils.getStackTrace(e)));
				try {
					comunicationError.setMensaje51(UtilidadesXML.marshalObjectWS(comunicacion));
				} catch (Exception e2) {
					e2.printStackTrace();
				}
				comunicationError = erroresTelevidaService.add(comunicationError);

				try {
					// ** Programar RE-Ejecución en diferido ** //
					HashMap<String, String> params = new HashMap<String, String>();
					params.put("id", comunicationError.getIdError51().toString());
					this.jobSchedulerService.programarEjecucion(SchedulerJobType.ERROR_TELEVIDA, params);
				} catch (Exception e2) {
					// Solo para que no haga rollback
					TelevidaServiceImpl.logger
							.error("Error programando re-ejecución: " + ExceptionUtils.getStackTrace(e2));
				}
			}

			respuesta = RespuestasTelevidaEnum.ERROR_EJECUTAR_PROCESO.getRespuesta();
			respuesta.setMensaje(getErrorMessage(ExceptionUtils.getStackTrace(e)));
			respuesta.setIdPeticion(comunicacion.getCabecera().getIdPeticion());
		}

		PeticionesPs peticionRespuestaPs = new PeticionesPs();
		peticionRespuestaPs.setCola99(PeticionesPs.COLA_RESPUESTA);
		peticionRespuestaPs.setIdPeticionOriginal99(comunicacion.getCabecera().getIdPeticion());
		peticionRespuestaPs.setNumAbonado99(comunicacion.getCabecera().getNumAbonado());
		peticionRespuestaPs.setMensaje99(UtilidadesXML.marshalObjectWS(respuesta));
		peticionRespuestaPs.setProcesado99(Constantes.CERO);
		peticionRespuestaPs = this.peticionesPsService.add(peticionRespuestaPs);

		// 4.- Añadir la respuesta a la cola de respuestas
		UtilJms.enviarJMS(peticionRespuestaPs.getIdPeticion99(),
				com.ejie.ad74a.constantes.Constantes.CONNECTION_FACTORY_JNDI_NAME,
				com.ejie.ad74a.constantes.Constantes.RESPUESTA_PRESTADOR_DESTINATION_JNDI_NAME, null, null);

	}

	@Override
	public void retramitarFromTelevidaError(Long id) throws Throwable {
		TelevidaServiceImpl.logger.debug("TelevidaServiceImpl - inicio retramitarFromTelevidaError id:" + id);
		ErroresTelevida error = new ErroresTelevida();
		error.setIdError51(id);
		error = erroresTelevidaService.find(error);
		if (null != error) {
			String mensaje = error.getMensaje51Str();
//			Comunicacion comunicacion = null;
			try {
				// Controlar si el error tiene se ha dado en la validación para tener que volver
				// a hacerla
				if ("VALIDACION".equals(error.getError51())) {
					Comunicacion comunicacion = (Comunicacion) UtilidadesXML.unmarshallerObject(mensaje,
							Comunicacion.class);
					this.televidaProccesService.proccesMessage(comunicacion);
				} else if (error.getSentido51() == 1) {
					// AD74A --> PS
					if (error.getMensaje51Str().startsWith("#")) {
						// El error se ha producido antes de enviar la comunicación
						String[] data = error.getMensaje51Str().replace("\n", "").substring(1).split("#"); // quitamos
																											// la
																											// primera #
						Solicitantes solicitante = new Solicitantes();
						solicitante.setIdSolicitante01(Long.valueOf(data[0]));
						Expedientes expediente = new Expedientes();
						try {
							expediente.setIdExpediente00(Long.valueOf(data[1]));
						} catch (Exception e) {
						}
						if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.ALTA.value()
								.equals(error.getTipomensaje51())) {
							this.prestadorWSService.enviarAlta(solicitante, expediente);
						} else if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.BAJA.value()
								.equals(error.getTipomensaje51())) {
							this.prestadorWSService.enviarBaja(solicitante, expediente);
						} else if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.DOMICILIO.value()
								.equals(error.getTipomensaje51())) {
							this.prestadorWSService.enviarCambioDomicilio(solicitante, expediente);
						} else if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.UPDATE.value()
								.equals(error.getTipomensaje51())) {
							this.prestadorWSService.enviarModificacion(solicitante, expediente);
						}
					} else {
						// El error se ha producido en la comunicación
						com.ejie.ad74a.ws.client.prestadorWS.Comunicacion comunicacion = (com.ejie.ad74a.ws.client.prestadorWS.Comunicacion) UtilidadesXML
								.unmarshallerObject(mensaje, com.ejie.ad74a.ws.client.prestadorWS.Comunicacion.class);
						if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.ALTA.value()
								.equals(comunicacion.getCabecera().getTipoComunicacion().value())) {
							this.prestadorWSService.relanzarEnviarAlta(comunicacion);
						} else if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.BAJA.value()
								.equals(comunicacion.getCabecera().getTipoComunicacion().value())) {
							this.prestadorWSService.relanzarEnviarBaja(comunicacion);
						} else if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.DOMICILIO.value()
								.equals(comunicacion.getCabecera().getTipoComunicacion().value())) {
							this.prestadorWSService.relanzarEnviarCambioDomicilio(comunicacion);
						} else if (com.ejie.ad74a.ws.client.prestadorWS.data.TipoComunicacionEnum.UPDATE.value()
								.equals(comunicacion.getCabecera().getTipoComunicacion().value())) {
							this.prestadorWSService.relanzarEnviarModificacion(comunicacion);
						}
					}

				} else if (error.getSentido51() == 0) {
					// PS --> AD74A
					Comunicacion comunicacion = (Comunicacion) UtilidadesXML.unmarshallerObject(mensaje,
							Comunicacion.class);
					this.procesar(comunicacion, true); // true para guardar un nuevo error pq el anterior se borra
														// después
//				televidaProccesService.proccesMessage(comunicacion);
				} else {
					throw new Exception("No se ha podido relanzar el error. Cosulte con el administrador");
				}
				// si ha ido bien, lo borramos de la tabla
				erroresTelevidaService.remove(error);
				TelevidaServiceImpl.logger.debug("Borrar error id:" + id);
			} catch (Exception e) {
				TelevidaServiceImpl.logger.error(
						"TelevidaServiceImpl - retramitarFromTelevidaError - ERROR:" + ExceptionUtils.getStackTrace(e));
				ManagerErrors.manageException(e);
			}
			TelevidaServiceImpl.logger.debug("PlateaJMSServiceImpl - fin retramitarFromJMSError");
		}

	}

	private String getErrorMessage(String error) {
		if (null != error && error.length() > 800) {
			error = error.substring(0, 799);
		}
		return error;
	}

}