package com.ejie.u74a.service;

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

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.u74a.dao.ArticuloDao;
import com.ejie.u74a.dao.OficinaDao;
import com.ejie.u74a.dao.PeticionDao;
import com.ejie.u74a.dao.RegistroEntradasSalidasDao;
import com.ejie.u74a.model.Articulo;
import com.ejie.u74a.model.CriteriosBusqueda;
import com.ejie.u74a.model.Oficina;
import com.ejie.u74a.model.Peticion;
import com.ejie.u74a.model.PeticionInforme;
import com.ejie.u74a.model.RegistroES;
import com.ejie.u74a.model.UbicacionInforme;
import com.ejie.u74a.model.UsuarioDetalles;
import com.ejie.u74a.util.Constants;
import com.ejie.u74a.util.Utilidades;
import com.ejie.u74a.util.exception.ParameterValidationException;

/**
 * Clase que implementa los servicios de acceso a los datos de peticiones.
 * 
 *  
 */
@Service(value = "peticionService")
@Transactional()
public class PeticionServiceImpl implements PeticionService {

	@Autowired()
	private PeticionDao dao;

	@Autowired()
	private OficinaDao oficinaDao;

	@Autowired()
	private ArticuloDao articuloDao;

	@Autowired()
	private RegistroEntradasSalidasDao registroESDao;

	@Resource(name = "appMessageSource")
	private ReloadableResourceBundleMessageSource messageSource;

	@Autowired()
	private MailService mailService;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.u74a.service.PeticionService#findByCriteria(CriteriosBusqueda)
	 */
	@Transactional(readOnly = true)
	@Override()
	public List<Peticion> findByCriteria(CriteriosBusqueda filtro) {
		return this.dao.findByCriteria(filtro);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.u74a.service.PeticionService#findByCountCriteria(CriteriosBusqueda)
	 */
	@Transactional(readOnly = true)
	@Override()
	public int findByCountCriteria(CriteriosBusqueda filtro) {
		return this.dao.findByCountCriteria(filtro);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.u74a.service.PeticionService#cambiarEstadoPeticion(List<Integer>,String)
	 */
	@Transactional()
	@Override()
	public String cambiarEstadoPeticion(List<Peticion> lstPeticiones) {

		for (Peticion peticion : lstPeticiones) {
			// String estado = peticionAux.getEstado();
			// Integer aceptadas = peticionAux.getNumAceptado();
			// Peticion peticion = this.dao.findByCodigo(peticionAux.getCodigoPeticion());

			// Chequear que estén todas pendientes
			/*
			 * if (!Constants.ESTADO_PENDIENTE.equals(peticion.getEstado())) { throw new
			 * ParameterValidationException(this.messageSource.getMessage("solicitud.errorNoPendiente", null,
			 * LocaleContextHolder.getLocale())); }
			 */

			Articulo datosStock = this.articuloDao.getDatosStockArticulo(peticion.getCodigoArticulo());

			int numEjemplaresSolicitados = 0;

			// if (Constants.ESTADO_ACEPTADA.equals(estado) && stockActualizado < stockMinimo) {// devuelvo un error
			if (Constants.ESTADO_ACEPTADA.equals(peticion.getEstado())) {

				numEjemplaresSolicitados = peticion.getNumAceptado()
						* (peticion.getNumEjemplaresCaja() > 0 ? peticion.getNumEjemplaresCaja() : 1);

				int stockActualizado = datosStock.getStock() - numEjemplaresSolicitados;

				// en caso de que el stock se vaya a quedar por debajo del stock mínimo
				if (stockActualizado < datosStock.getStockMin()) {// devuelvo un error

					String descripcionIdioma = this.articuloDao.getDescripcionIdiomasArticulo(peticion
							.getCodigoArticulo());

					Object[] msgArgs = { peticion.getDescripcionMaterial() + " - " + descripcionIdioma };
					throw new ParameterValidationException(this.messageSource.getMessage("solicitud.errorStock",
							msgArgs, LocaleContextHolder.getLocale()));
				}
			}

			int numAfectadas = this.dao.cambiarEstadoPeticion(peticion);

			// Actualizar stock para cada artículo, si han sido aceptadas
			if (numAfectadas > 0 && Constants.ESTADO_ACEPTADA.equals(peticion.getEstado())) {
				UsuarioDetalles usuario = Utilidades.getDetallesUsuario();
				int codigoUsuarioModificador = Integer.parseInt(usuario.getUsername());
				Date fechaModificacion = new Date();

				// TODO esta parte se puede llevar al service de registros?
				numAfectadas = this.articuloDao.actualizarStockArticulo(peticion.getCodigoArticulo(), true,
						numEjemplaresSolicitados, codigoUsuarioModificador, fechaModificacion);

				if (numAfectadas > 0) {
					RegistroES registroES = new RegistroES();
					registroES.setCodigoArticulo(peticion.getCodigoArticulo());
					registroES.setCodigoOficina(peticion.getCodigoSolicitante());
					registroES.setFechaEntradaSalida(fechaModificacion);
					registroES.setTipo(Constants.TIPO_ES_SALIDA);
					registroES.setSubtipo(Constants.SUBTIPO_ES_PETICION);
					registroES.setCodigoPeticion(peticion.getCodigoPeticion());
					registroES.setNumEjemplares(numEjemplaresSolicitados);

					this.registroESDao.insertarRegistroES(registroES);
				} else {
					// TODO throw
				}
			}
			// lstPeticiones.add(peticion);
		}

		// envio los mails a las oficinas
		for (Peticion peticion : lstPeticiones) {
			Oficina oficina = this.oficinaDao.findByCodigo(peticion.getCodigoSolicitante());
			if (oficina != null) {

				String asunto = this.messageSource.getMessage("solicitud.email.asunto", null,
						LocaleContextHolder.getLocale());

				List<String> args = new ArrayList<String>();

				if (Constants.ESTADO_ACEPTADA.equals(peticion.getEstado())) {

					args.add(this.messageSource.getMessage("solicitud.email.body.aceptada", null,
							LocaleContextHolder.getLocale()));

				} else {
					args.add(this.messageSource.getMessage("solicitud.email.body.rechazada", null,
							LocaleContextHolder.getLocale()));
				}

				args.add(peticion.getDescripcionMaterial());
				args.add(this.articuloDao.getDescripcionIdiomasArticulo(peticion.getCodigoArticulo()));
				args.add(Integer.toString(peticion.getNumPedido()));

				String modo = "";
				if (peticion.getNumEjemplaresCaja() > 0) {
					modo = this.messageSource.getMessage("solicitud.email.body.cajas", null,
							LocaleContextHolder.getLocale());
				} else {
					modo = this.messageSource.getMessage("solicitud.email.body.ejemplares", null,
							LocaleContextHolder.getLocale());
				}
				args.add(modo);
				args.add(Integer.toString(peticion.getNumAceptado()));
				args.add(modo);

				String body = this.messageSource.getMessage("solicitud.email.body", args.toArray(),
						LocaleContextHolder.getLocale());

				this.mailService.sendMail(oficina.getEmail(), asunto, body);
			}
		}

		return "{\"resultado\": \"OK\"}";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.u74a.service.PeticionService#generarInforme(java.util.List)
	 */
	@Override()
	public List<UbicacionInforme> generarInforme(List<Integer> codigosPeticionLst) {

		List<UbicacionInforme> lstUbicacionesInforme = new ArrayList<UbicacionInforme>();

		if (codigosPeticionLst != null) {

			UbicacionInforme ubicacionInforme = null;
			PeticionInforme peticionInforme = null;
			for (Integer codigoPeticion : codigosPeticionLst) {
				peticionInforme = this.dao.findPeticionInformeByCodigo(codigoPeticion);

				// Chequear que estén todas aceptadas
				if (!Constants.ESTADO_ACEPTADA.equals(peticionInforme.getEstado())) {
					throw new ParameterValidationException(this.messageSource.getMessage("solicitud.errorNoAceptada",
							null, LocaleContextHolder.getLocale()));
				}

				ubicacionInforme = this.dao.findUbicacionByCodigo(codigoPeticion);

				if (!lstUbicacionesInforme.contains(ubicacionInforme)) {
					lstUbicacionesInforme.add(ubicacionInforme);
					ubicacionInforme.getPeticionesInforme().add(peticionInforme);
				} else {
					UbicacionInforme ubicacionInformeExistente = lstUbicacionesInforme.get(lstUbicacionesInforme
							.indexOf(ubicacionInforme));
					ubicacionInformeExistente.getPeticionesInforme().add(peticionInforme);
				}

			}

		}

		return lstUbicacionesInforme;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.u74a.service.PeticionService#findByCriteriaMisSolicitudes(com.ejie.u74a.model.CriteriosBusqueda)
	 */
	@Transactional(readOnly = true)
	@Override()
	public List<Peticion> findByCriteriaMisSolicitudes(CriteriosBusqueda filtro) {
		return this.dao.findByCriteriaMisSolicitudes(filtro);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.ejie.u74a.service.PeticionService#findByCountCriteriaMisSolicitudes(com.ejie.u74a.model.CriteriosBusqueda)
	 */
	@Transactional(readOnly = true)
	@Override()
	public int findByCountCriteriaMisSolicitudes(CriteriosBusqueda filtro) {
		return this.dao.findByCountCriteriaMisSolicitudes(filtro);
	}

	@Transactional(readOnly = true)
	@Override()
	public Peticion findDetalleByCodigo(int codigoPeticion) {
		return this.dao.findDetalleByCodigo(codigoPeticion);
	}
}
