package com.ejie.ad74a.tareas.service;

import java.text.ParseException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ejie.ad74a.async.NisaeAsyncProcessService;
import com.ejie.ad74a.dao.ExpedientesDao;
import com.ejie.ad74a.dao.InformesDao;
import com.ejie.ad74a.dao.SolicitantesDao;
import com.ejie.ad74a.exceptions.ConstantesCodeError;
import com.ejie.ad74a.exceptions.ManagerErrors;
import com.ejie.ad74a.jms.util.ModelApplicationParser;
import com.ejie.ad74a.model.DocTemporales;
import com.ejie.ad74a.model.DocumentosInforme;
import com.ejie.ad74a.model.Expedientes;
import com.ejie.ad74a.model.Informes;
import com.ejie.ad74a.model.Solicitantes;
import com.ejie.ad74a.model.Soporte;
import com.ejie.ad74a.service.InformesService;
import com.ejie.ad74a.service.SoporteService;
import com.ejie.ad74a.service.documentos.DocumentosService;
import com.ejie.ad74a.service.tramitacion.TramitacionService;
import com.ejie.ad74a.util.comun.Utilidades;
import com.ejie.ad74a.util.comun.UtilidadesFecha;
import com.ejie.ad74a.util.constantes.Constantes;
import com.ejie.ad74a.util.constantes.EstadosExpedienteEnum;
import com.ejie.ad74a.util.constantes.ProcedimientosEnum;
import com.ejie.ad74a.util.constantes.TareasEnum;
import com.ejie.ad74a.util.constantes.TiposDocumentoRoleEnum;
import com.ejie.ad74a.util.constantes.modelos.TipoSolicitantes;
import com.ejie.ad74a.ws.client.platea.model.task.Task;
import com.ejie.ad74a.ws.client.platea.service.PlateaService;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TTask;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TTaskType;

/**
 * Gestión de la Tarea de Apertura de Expediente
 * 
 * @author IBERMATICA
 */
@Service(value = "tareaAperturaService")
public class TareaAperturaServiceImpl implements TareaAperturaService {

	private static final Logger logger = LoggerFactory.getLogger(TareaAperturaServiceImpl.class);

	@Autowired
	private PlateaService plateaService;

	@Autowired
	private ExpedientesDao expedientesDao;

	@Autowired
	private SolicitantesDao solicitantesDao;

	@Autowired
	private TramitacionService tramitacionService;

	@Autowired
	private InformesService informesService;

	@Autowired
	private InformesDao informesDao;

	@Autowired
	private DocumentosService documentosService;

	@Autowired
	private NisaeAsyncProcessService nisaeAsyncProcessService;

	@Autowired
	private SoporteService soporteService;

	/**
	 * Método que gestiona el evento de Tarea Sugerida
	 * 
	 */
	public void tareaSugerida(Task task) throws Throwable {
		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.tareaSugerida -" + task.getMailboxTaskID() + "- inicio ");

		String numRegistro = ModelApplicationParser.getNumRegistryFromTask(task);

		// si estamos tratando la tarea de apertura, hay que asegurarse que se ha
		// ejecutado la presentacion de la solicitud
		Expedientes expediente = this.inicioSolicitudOk(task.getFolderID());
		if (null != expediente) {
			TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.tareaSugerida #1# -"
					+ task.getMailboxTaskID() + "- expediente.urgencia00 = " + expediente.getUrgencia00());
			// [jbhg] actualizar siempre el estado del expediente a "PDTE APERTURA" si no lo
			// estaba ya antes.
			expediente.setEstados(EstadosExpedienteEnum.PEND_APERTURA.getEstado());
			this.expedientesDao.updateEstado(expediente);

			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.tareaSugerida #2# -" + task.getMailboxTaskID()
							+ "- expediente.urgencia00 = " + this.expedientesDao.find(expediente).getUrgencia00());

			// almacenamos el tramite y la tarea
			this.tramitacionService.tratamientoTramiteTareaSugerida(task, numRegistro, expediente);

			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.tareaSugerida #3# -" + task.getMailboxTaskID()
							+ "- expediente.urgencia00 = " + this.expedientesDao.find(expediente).getUrgencia00());

			String folderNumber = this.saveFolderNumber(task.getFolderID(), task.getProcedureID());
			expediente.setNumExpediente00(folderNumber);

			// reasignamos la tarea de apertura al buzon correspondiente
			this.reasignarTarea(task.getMailboxTaskID(), expediente.getIdProcedimiento00());

			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.tareaSugerida #4# -" + task.getMailboxTaskID()
							+ "- expediente.urgencia00 = " + this.expedientesDao.find(expediente).getUrgencia00());

			// ejecutamos la tarea
			this.ejecutarTareaAutomatica(task, expediente.getNumExpediente00());

			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.tareaSugerida #5# -" + task.getMailboxTaskID()
							+ "- expediente.urgencia00 = " + this.expedientesDao.find(expediente).getUrgencia00());

			try {
				// grabamos la fecha de apertura
				String openDate = task.getTaskInfo().getOpenTaskData().getOpenDate();

				if (null != openDate && openDate.contains("-")) {
					expediente.setfAperturaExp00(UtilidadesFecha.formatearStringToDateFormat(openDate,
							Constantes.DATE_FORMAT_PLATEA_XML_EVENTS));
				} else if (null != openDate && openDate.contains("/")) {
					expediente.setfAperturaExp00(UtilidadesFecha.formatearStringToDateFormat(openDate,
							Constantes.DATE_FORMAT_TIMESTAMP_MASK_DEFAULT));
				}
				this.expedientesDao.updateFApertura(expediente);
			} catch (ParseException e) {
				logger.error("Error al parsear la fecha de apertura");
			}

			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.tareaSugerida #6# -" + task.getMailboxTaskID()
							+ "- expediente.urgencia00 = " + this.expedientesDao.find(expediente).getUrgencia00());
		} else {
			ManagerErrors.manageError(ConstantesCodeError.MENSAJE_ERROR_TAREA_APERTURA_SOLICITUD_NO_PRESENTADA);
		}

		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.tareaSugerida -" + task.getMailboxTaskID() + "- inicio ");
	}

	/**
	 * Método que gestiona el evento de Tarea Ejecutada
	 */
	public void tareaEjecutada(Task task) throws Throwable {
		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.tareaEjecutada -" + task.getMailboxTaskID() + "- inicio ");
		Expedientes expTrazaFiltro = new Expedientes();
		expTrazaFiltro.setFolderId00(task.getFolderID());
		List<Expedientes> expList = expedientesDao.findAll(expTrazaFiltro, null);
		Expedientes expTraza = expList.size() > 0 ? expList.get(0) : new Expedientes();
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.tareaEjecutada #1# -" + task.getMailboxTaskID()
				+ "- expediente.urgencia00 = " + this.expedientesDao.find(expTraza).getUrgencia00());

		// actualizamos el tramite y la tarea
		this.tramitacionService.tratamientoTramiteTareaEjecutada(task, false);

		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.tareaEjecutada #2# -" + task.getMailboxTaskID()
				+ "- expediente.urgencia00 = " + this.expedientesDao.find(expTraza).getUrgencia00());

		String procedureId = task.getProcedureID();
		// ** En función del ID de la tarea se especifica la acción ** //
		switch (ProcedimientosEnum.getById(procedureId)) {

		case ALTA:

			// hacer match con informe social
			matchInformeSocial(task.getFolderID());

			// FASE I intercambio PS:
			// - crear un registro para soporte
			// - idioma solcitante = idioma servicio
			// - tipo beneficiario = "TITULAR A" -- lo comentamos de momento ya que no
			// influye

			Solicitantes solicitante = this.solicitantesDao.findBeneficiarioByFolderId(task.getFolderID());
			Soporte newSoporte = new Soporte();
			newSoporte.setIdSolicitante22(solicitante.getIdSolicitante01());
			newSoporte.setIdNivelSoporte22(Long.valueOf(Constantes.UNO));
			newSoporte.setUsuAlta22(com.ejie.ad74a.constantes.Constantes.COD_APLICACION);
			this.soporteService.add(newSoporte);

			solicitante.setIdiomaSolicitante01(solicitante.getIdiomaServicio01());
			this.solicitantesDao.updateIdioma(solicitante);

//			solicitante.setTipoBeneficiario01(TipoSolicitantes.TipoBeneficiario01.TITULAR_A.getId());
//			this.solicitantesDao.updateTipoBeneficiario(solicitante);
			// Fin FASE I intercambio PS

			// ** Apertura del plazo de desistimiento ** //
			this.tramitacionService.sugerirTarea(task, TareasEnum.APER_PLAZO_DESIS);

			// ** Estudio por Apertura **/
			this.tramitacionService.sugerirTarea(task, TareasEnum.ESTUDIO);

			break;
		case BAJA:

			// ** Apertura del plazo de desistimiento ** //
			this.tramitacionService.sugerirTarea(task, TareasEnum.APER_PLAZO_DESIS);

			// ** Estudio por Apertura **/
			this.tramitacionService.sugerirTarea(task, TareasEnum.ESTUDIO);

			break;
		case INFORME:

			// ** Estudio por Apertura **/
			this.tramitacionService.sugerirTarea(task, TareasEnum.ESTUDIO);

			break;
		case REVISION_PRECIO:

			// ** Apertura del plazo de desistimiento ** //
			this.tramitacionService.sugerirTarea(task, TareasEnum.APER_PLAZO_DESIS);
			// hacemos la aportacion del expediente

			Expedientes exp = new Expedientes();
			exp.setFolderId00(task.getFolderID());
			exp = this.expedientesDao.findAll(exp, null).get(0);
//			if (Constantes.TipoSolicitud.SOLICITUD_DE_OFICIO.equals(exp.getDeOficio00())) {
//				TareaAperturaServiceImpl.logger.info(
//						"TareaAperturaServiceImpl.tareaEjecutada - inicioDeOficio - aportacionInteroperabilidad ");

			// TODO revisar, no funciona
//				this.plateaService.aportacionInteroperabilidad(exp);
//			}

			// ** Estudio por Apertura **/
			this.tramitacionService.sugerirTarea(task, TareasEnum.ESTUDIO);

			break;

		case MODIFICACION:

			// hacer match con informe social
			matchInformeSocial(task.getFolderID());

			// ** Estudio por Apertura **/
			this.tramitacionService.sugerirTarea(task, TareasEnum.ESTUDIO);

			break;
		case NOTIFICACION_LIQUIDACION:

			// Ejecutar tarea de acuse de notificacion de liquidacion
			// Cambiamos, y sugerimos el aporte de la carta de liquidacion previamente.
			this.tramitacionService.sugerirTarea(task, TareasEnum.APOR_CARTA_LIQUID);

			break;
		default:
			break;
		}

		String procedureID = task.getProcedureID();
		if (procedureID.equalsIgnoreCase(Constantes.Procedimientos.ALTA)
				|| procedureID.equalsIgnoreCase(Constantes.Procedimientos.MODIFICACION)
				|| procedureID.equalsIgnoreCase(Constantes.Procedimientos.REVISION_PRECIO)) {
			// ** aprovechamos esto para consultar los datos de interoperabilidad ** //
			this.consultaInteroperabilidad(task.getFolderID(), task.getProcedureID());
		}

		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.tareaEjecutada -" + task.getMailboxTaskID() + "- fin ");

	}

	/**
	 * Preparación de la tarea
	 */
	public TTask prepararTarea(String taskGUID) throws Throwable {
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.prepararTarea -" + taskGUID + "- inicio ");

		// preparamos tarea de Platea
		TTask tTask = plateaService.prepareTask(taskGUID, TTaskType.APERTURA);

		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.prepararTarea -" + tTask.getTaskID() + "-" + taskGUID + "- fin ");
		return tTask;
	}

	/**
	 * Ejecución de la tarea
	 */
	public TTask ejecutarTarea(TTask tTask) throws Throwable {
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.ejecutarTarea -" + tTask.getTaskID() + "-"
				+ tTask.getMailboxTaskID() + "- inicio");

		tTask = plateaService.doTask(TareasEnum.getTaskType(tTask.getTaskID()), tTask);

		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.ejecutarTarea -" + tTask.getTaskID() + "-"
				+ tTask.getMailboxTaskID() + "- fin");

		return tTask;
	}

	/**
	 * Ejecución de la tarea de forma automática
	 */
	public void ejecutarTareaAutomatica(String taskGUID) throws Throwable {

	}

	private void ejecutarTareaAutomatica(Task task, String folderNumber) throws Throwable {
		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.ejecutarTareaApertura -" + task.getMailboxTaskID() + "- Inicio");
		com.ejie.ad74a.ws.client.platea.tareasTramitacion.TTask taskP = null;
		try {
			// Preparación de la tarea
			taskP = this.prepararTarea(task.getMailboxTaskID());

			// Número de expediente de negocio
			taskP.setFolderNumber(folderNumber);

			// Gestor
			// if (null == taskP.getProcessingRoleID()) {
			taskP.setProcessingRoleID(Constantes.PROCESSING_ROLE_ID);
			// }

			// Incluimos SenderId=CodApp
			taskP.setSenderID(TareasUtils.getSenderIdAutomatico());

		} catch (Throwable e) {
			ManagerErrors.manageException(e,
					ConstantesCodeError.MENSAJE_ERROR_PREPARAR_TAREA + " "
							+ TareasEnum.getEnumByTaskId(task.getTaskID()).getTaskId(),
					null, ConstantesCodeError.CODE_ERROR_PREPARAR_TAREA, null);
		}

		try {
			// ** Ejecución de la tarea ** //
			TareaAperturaServiceImpl.logger.info(
					"TareaAperturaServiceImpl.ejecutarTareaApertura " + task.getMailboxTaskID() + "- Ejecutar Tarea");
			taskP = this.ejecutarTarea(taskP);
		} catch (Throwable e) {
			ManagerErrors.manageException(e,
					ConstantesCodeError.MENSAJE_ERROR_EJECUTAR_TAREA + " "
							+ TareasEnum.getEnumByTaskId(task.getTaskID()).getTaskId(),
					null, ConstantesCodeError.CODE_ERROR_EJECUTAR_TAREA, null);
		}

		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.ejecutarTareaApertura " + task.getMailboxTaskID() + "- Fin");
	}

	private Expedientes inicioSolicitudOk(String folderId) {
		Expedientes expediente = new Expedientes();
		expediente.setFolderId00(folderId);

		boolean incioSolicitudTratado = false;
		int espera = 0;
		List<Expedientes> listaExpedientes = null;
		Expedientes expedienteRes = null;
		while (!incioSolicitudTratado && espera < 10) {
			listaExpedientes = expedientesDao.findAll(expediente, null);
			if (null != listaExpedientes && listaExpedientes.size() > 0) {
				incioSolicitudTratado = true;
				expedienteRes = listaExpedientes.get(0);
				break;
			}
			try {
				TimeUnit.SECONDS.sleep(3);
				espera++;
			} catch (InterruptedException e) {
				TareaAperturaServiceImpl.logger.error("Error en la comprobacion en la tarea de apertura");
			}
		}
		return expedienteRes;
	}

	/********************************/

	private String saveFolderNumber(String folderId, String procedure) throws Exception {
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.saveFolderNumber - Inicio");
		int codSeqInt = this.expedientesDao.getNumberFolderSequence(procedure);

		Expedientes expediente = new Expedientes();
		expediente.setFolderId00(folderId);
		String folderNumber = TareasUtils.generateFolderNumber(codSeqInt, procedure);
		List<Expedientes> listaExpedientes = expedientesDao.findAll(expediente, null);
		if (null != listaExpedientes && listaExpedientes.size() > 0) {
			expediente = listaExpedientes.get(0);
			TareaAperturaServiceImpl.logger.info("El expediente existe");
			// actualizamos el Folder Number
			expediente.setNumExpediente00(folderNumber);
			expediente.setFolderId00(folderId);
			expediente.setUsuModif00(com.ejie.ad74a.constantes.Constantes.COD_APLICACION);
			try {
				expedientesDao.updateFolderNumber(expediente);
			} catch (Exception e) {
				TareaAperturaServiceImpl.logger.error("Error al grabar el folder number");
				ManagerErrors.manageException(e, ConstantesCodeError.MENSAJE_ERROR_GRABAR_FOLDER_NUMBER, null,
						ConstantesCodeError.CODE_ERROR_GRABAR_FOLDER_NUMBER, null);
			}
		} else {
			ManagerErrors.manageError(ConstantesCodeError.MENSAJE_ERROR_SOLICITUD_NO_PRESENTADA);
		}

		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.saveFolderNumber - Fin folderNumber: " + folderNumber);
		return folderNumber;

	}

	private void reasignarTarea(String taskGuid, String procedureId) throws Throwable {
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.reasignarTarea - Inicio");
		try {
			// Lanzamos la ejecucion de la tarea
			String mailBox = TareasUtils.getBuzonByProdedure(procedureId);
			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.reasignarTarea - taskGUID: " + taskGuid + " - mailBox: " + mailBox);
			this.plateaService.assignTasks(taskGuid, mailBox);
		} catch (Throwable e) {
			ManagerErrors.manageException(e, ConstantesCodeError.CODE_ERROR_REASIGNAR_TAREA_ESTUDIO_APERTURA, null,
					ConstantesCodeError.CODE_ERROR_REASIGNAR_TAREA_ESTUDIO_APERTURA, null);
		}
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.reasignarTarea - Fin");
	}

	private void consultaInteroperabilidad(String folderID, String procedureID) {
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.consultaInteroperabilidad - folderID: "
				+ folderID + " _ procedureID: " + procedureID);
		try {
			this.nisaeAsyncProcessService.authorizationResultConsolidationAsync(folderID, procedureID);
		} catch (Exception e) {
			TareaAperturaServiceImpl.logger.error("Error TareaAperturaServiceImpl.consultaInteroperabilidad");
		}
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.consultaInteroperabilidad Salir ");
	}

	/**
	 * Hacemos el match por informe social si existe.De hacerlo, se sugiere una
	 * tarea de aportacion de documentacion. Además, almacenamos el doc en una tabla
	 * temporal, para que al ejecutar la tarea podamos aportarlo
	 * 
	 * @param folderID
	 */
	private void matchInformeSocial(String folderID) {
		TareaAperturaServiceImpl.logger
				.info("TareaAperturaServiceImpl.matchInformeSocial Inicio - folderID: " + folderID);
		Solicitantes solicitante = this.solicitantesDao.findBeneficiarioByFolderId(folderID);
		Informes informe = this.informesService.getInformeSocialSinMatchByNIF(solicitante.getIdentificador01(), true);
		if (null != informe && null != informe.getIdInforme16()) {
			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.matchInformeSocial - relacionInformePorMatch idSolicitante: "
							+ solicitante.getIdSolicitante01());
			TareaAperturaServiceImpl.logger
					.info("TareaAperturaServiceImpl.matchInformeSocial - relacionInformePorMatch idExpediente: "
							+ solicitante.getExpSolicitud().getIdExpediente00());
			// actualizar el expediente y el solicitante en el informe social
			informe.setIdBeneficiario16(solicitante.getIdSolicitante01());
			informe.setIdExpediente16(solicitante.getExpSolicitud().getIdExpediente00());

			this.informesDao.relacionInformePorMatch(informe);

			DocumentosInforme docInform = informe.getDocumentosInforme();
			if (null != docInform && null != docInform.getIdDocInforme17()
					&& !Utilidades.esBlancoNulo(docInform.getOid17())) {

				TareaAperturaServiceImpl.logger
						.info("TareaAperturaServiceImpl.matchInformeSocial - Se hace la aportacion oid:"
								+ docInform.getOid17());

				DocTemporales docTemp = new DocTemporales();
				docTemp.setNombreDoc72(docInform.getNombreDoc17());
				docTemp.setRutapif72(docInform.getUrlRuta17());
				docTemp.setFolderId72(folderID);
				docTemp.setOid72(docInform.getOid17());
				docTemp.setUsuAportacion72(com.ejie.ad74a.constantes.Constantes.COD_APLICACION);
				docTemp.setIdTipoDoc72(TiposDocumentoRoleEnum.INFORME_SOCIAL.getId());
				docTemp.setExterno72(1);
				this.documentosService.aportarDocumento(docTemp);

			}

		}
		TareaAperturaServiceImpl.logger.info("TareaAperturaServiceImpl.matchInformeSocial Salir ");
	}

}
