package com.mx.dla.dda.contrato.transaccion.titulos.bos;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

import com.mx.dla.dda.catalogos.dtos.CatalogoDTO;
import com.mx.dla.dda.contrato.titulo.constants.TipoCambioTitulo;
import com.mx.dla.dda.contrato.titulo.dtos.Lista;
import com.mx.dla.dda.contrato.titulo.exception.TituloException;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.contrato.transaccion.titulos.daos.TituloTransDAO;
import com.mx.dla.dda.contrato.transaccion.titulos.dtos.TituloTransDB;
import com.mx.dla.dda.contrato.transaccion.titulos.dtos.TituloTransaccionDTO;
import com.mx.dla.global.bos.BaseBO;

//Clase que implementa las funciones basicas de la pantalla de titulos
@Component
public class TituloTranGridBO extends BaseBO {

	@Autowired
	private TituloTranRules tituloRules;

	@Autowired
	private TituloTransDAO tituloDAO;

	private List<CatalogoDTO> filiales;
	private List<CatalogoDTO> categorias;
	private List<CatalogoDTO> generosA;
	private List<CatalogoDTO> generosB;
	private List<CatalogoDTO> tiers;
	private List<CatalogoDTO> catSeries;

	public String agregarTitulo(Long idContrato, Long idLista, TituloTransaccionDTO titulo) throws TituloException {
		String serie = null;
		titulo = this.obtenerDatosComplementarios(idLista, idContrato, titulo);

		logger.info("{}", titulo);

		try {
			tituloRules.validaEntrada(titulo);
		} catch (ResultMapException e) {
			logger.error("Error. {}", e);
		} catch (TransaccionException e) {
			logger.error("Error. {}", e);
		} catch (SQLException e) {
			logger.error("Error. {}", e);
		}
		this.guardaTitulo(titulo);
		return serie;
	}

	public void altaSeriesAuto(Long idContrato, Long idLista, TituloTransaccionDTO titulo) throws TituloException {
		int numEpisodios = Integer.parseInt(titulo.getEpisodio());
		logger.debug("" + numEpisodios);
		String nombre = titulo.getNombreUnico() + ": Episodio # ";
		titulo = this.obtenerDatosComplementarios(idLista, idContrato, titulo);

		for (int i = 1; i <= numEpisodios; i++) {
			String name = nombre + i;
			titulo.setNombreEstandar(name);
			titulo.setEpisodio("" + i);
			this.guardaTitulo(titulo);
		}
	}

	public TituloTransaccionDTO guardaTitulo(TituloTransaccionDTO titulo) throws TituloException {
		logger.debug("titulo a: {}", titulo);
		TituloTransDB tit = TituloTranUtil.TituloDTO2BD(titulo, this.filiales, this.categorias, this.generosA,
				this.generosB, this.tiers, this.catSeries);
		logger.debug("titulo b: {}", tit);

		tituloDAO.guardarTituloTrans(tit);
		titulo.setIdTituloCnt(tit.getIdTituloCnt());
		return titulo;
	}

	public void editarTitulo(Long idContrato, Long idLista, TituloTransaccionDTO titulo)
			throws TituloException, ResultMapException, TransaccionException, SQLException {

		titulo = this.obtenerDatosComplementarios(idLista, idContrato, titulo);

		logger.info("{}", titulo);

		tituloRules.validaEntrada(titulo);

		if (!this.actualizarTituloEnmienda()) {
			TituloTransDB tit = TituloTranUtil.TituloDTO2BD(titulo, this.filiales, this.categorias, this.generosA,
					this.generosB, this.tiers, this.catSeries);
			logger.info("{}", tit);

			tituloDAO.editarTituloTrans(tit);
		}
	}

	public void eliminarTitulo(Long idTitulo) {

		tituloDAO.borrarTitulo(idTitulo);
	}

	public String cambioMultipleTitulo(Long idContrato, Long idLista, TituloTransaccionDTO titulo, List<Long> ids,
			String cambio) throws TituloException, TransaccionException, SQLException {

		Boolean bloque = ids.size() < 1000 ? true : false;
		String mensaje = "";
		titulo.setIdContrato(idContrato);
		try {
			if (TipoCambioTitulo.CATEGORIA.name().equals(cambio)) {
				logger.info("Categoria");
				TituloTransDB tit = TituloTranUtil.TituloDTO2BD(titulo, this.filiales, this.categorias, this.generosA,
						this.generosB, this.tiers, this.catSeries);

				if (bloque)
					tituloDAO.actualizarCategoriaTrans(tit.getIdCategoria(), null, bloque, ids);
				else {
					for (Long index : ids)
						tituloDAO.actualizarCategoriaTrans(tit.getIdCategoria(), index, bloque, null);
				}
			} else if (TipoCambioTitulo.VENTANA.name().equals(cambio)) {
				logger.info("Ventana");

				tituloRules.validaVentanaTitulo(titulo);

				if (bloque)
					tituloDAO.actualizarVentanaTrans(titulo.getFechaInicio(), titulo.getFechaFin(), null, bloque, ids);
				else {
					for (Long index : ids)
						tituloDAO.actualizarVentanaTrans(titulo.getFechaInicio(), titulo.getFechaFin(), index, bloque,
								null);
				}
			} else if (TipoCambioTitulo.HVRD.name().equals(cambio)) {
				logger.info("Hvrd");
				logger.info("{}", ids);

				tituloRules.validaHvrdTitulo(titulo,
						TituloTranUtil.TituloBD2DTO(tituloDAO.obtenTitulos(ids, null, Lista.MIRROR)));

				if (bloque)
					tituloDAO.actualizarHvrdTrans(titulo.getHvrd(), null, bloque, ids);
				else {
					for (Long index : ids)
						tituloDAO.actualizarHvrdTrans(titulo.getHvrd(), index, bloque, null);
				}
			}
			return mensaje;
		} catch (TituloException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		} catch (TransaccionException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public <T> void print(final List<T> lista) {
		for (T item : lista)
			logger.info("{}", item);
	}

	public List<TituloTransaccionDTO> obtenerTitulos(String prefix, Long idLista)
			throws ResultMapException, SQLException, TransaccionException {

		try {
			List<TituloTransDB> titulos = new ArrayList<TituloTransDB>();

			List<TituloTransDB> totalFila = tituloDAO.buscaTotalesListaTran(prefix, idLista);
			titulos.addAll(totalFila);
			logger.info("*** totalFila: {} +++");
			print(totalFila);

			logger.info("");

			List<TituloTransDB> filasNoAgrupadas = tituloDAO.buscaDetallePeliculasTran(idLista);
			titulos.addAll(filasNoAgrupadas);
			logger.info("*** filasPeliculas: {} +++");
			print(filasNoAgrupadas);

			logger.info("");

			List<TituloTransDB> titulosCapitulo1 = tituloDAO.buscaSeries1CapituloTrans(idLista, prefix);
			logger.info("*** filasUnCapitulo: {} +++");
			print(titulosCapitulo1);

			logger.info("");

			List<TituloTransDB> titulosAgrupados = tituloDAO.buscaTotalesSerie(idLista, null, prefix);
			logger.info("*** titulosAgrupados: {} +++");
			print(titulosAgrupados);

			logger.info("");

			List<TituloTransDB> titulosRestados = this.removerSeries1Capitulo(titulosCapitulo1, titulosAgrupados);
			titulos.addAll(titulosRestados);
			logger.info("*** titulosRestados: {} +++");
			print(titulosRestados);

			logger.info("");

			List<TituloTransaccionDTO> titulosDto = new ArrayList<TituloTransaccionDTO>();
			for (TituloTransDB t : titulos)
				titulosDto.add(TituloTranUtil.TituloBD2DTO(t));

			logger.info("*** titulosTransformados: {} +++");
			print(titulosDto);
			return titulosDto;
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

	}

	public List<TituloTransDB> removerSeries1Capitulo(List<TituloTransDB> titulosCapitulo1,
			List<TituloTransDB> titulosAgrupados) {
		List<TituloTransDB> titulos = new ArrayList<TituloTransDB>();

		for (TituloTransDB s : titulosCapitulo1) {
			int i = 0;
			for (TituloTransDB tt : titulosAgrupados) {
				if (tt.getNombreUnico().equals(s.getNombreUnico())) {
					titulosAgrupados.remove(i);
					break;
				}
				i++;
			}
		}
		titulos.addAll(titulosCapitulo1);
		titulos.addAll(titulosAgrupados);
		return titulos;
	}

	public List<TituloTransaccionDTO> obtenerTitulosSeries(String prefix, Long idLista, String nombreUnico)
			throws ResultMapException, SQLException, TransaccionException {
		List<TituloTransDB> titulos = new ArrayList<TituloTransDB>();

		try {
			titulos.addAll(tituloDAO.buscaTotalesSerie(idLista, nombreUnico, prefix));
			titulos.addAll(tituloDAO.buscaDetalleSeriesTran(idLista, nombreUnico));
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		List<TituloTransaccionDTO> titulosDto = new ArrayList<TituloTransaccionDTO>();

		for (TituloTransDB t : titulos)
			titulosDto.add(TituloTranUtil.TituloBD2DTO(t));

		if (!titulosDto.isEmpty())
			titulosDto.get(0).setAgrupable(0);
		return titulosDto;
	}

	public List<TituloTransaccionDTO> listarPrincipalTitulos(String prefix, Long idLista)
			throws ResultMapException, SQLException, TransaccionException {

		TituloTransaccionDTO parametros = new TituloTransaccionDTO();
		parametros.setIdLista(idLista);
		logger.info("listarPrincipalTitulos");
		List<TituloTransDB> titulos = new ArrayList<TituloTransDB>();

		try {
			titulos.addAll(tituloDAO.listaTitulosPrincipal(parametros, "L"));
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		logger.info("{}", titulos);

		return TituloTranUtil.TituloBD2DTO(titulos);

	}

	public List<TituloTransaccionDTO> listarSeriesTitulos(String prefix, Long idLista, String nombreUnico)
			throws ResultMapException, SQLException, TransaccionException {

		TituloTransaccionDTO parametros = new TituloTransaccionDTO();
		parametros.setIdLista(idLista);
		parametros.setNombreUnico(nombreUnico);
		logger.info("listarSeriesTitulos");
		List<TituloTransDB> titulos = new ArrayList<TituloTransDB>();
		try {
			titulos.addAll(tituloDAO.listaTitulosPrincipal(parametros, "H"));
			logger.info("{}", titulos);
			titulos.addAll(tituloDAO.listaTitulosSeries(parametros, "L"));
			logger.info("{}", titulos);
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		return TituloTranUtil.TituloBD2DTO(titulos);

	}

	public List<TituloTransaccionDTO> listarDetalleTitulos(String prefix, Long idLista, String nombreUnico, String idBv)
			throws ResultMapException, SQLException, TransaccionException {

		TituloTransaccionDTO parametros = new TituloTransaccionDTO();
		parametros.setIdLista(idLista);
		parametros.setNombreUnico(nombreUnico);
		parametros.setIdBv(idBv);
		logger.info("listarDetalleTitulos");
		List<TituloTransDB> titulos = new ArrayList<TituloTransDB>();
		try {
			titulos.addAll(tituloDAO.listaTitulosSeries(parametros, "H"));
			logger.info("{}", titulos);
			titulos.addAll(tituloDAO.listaTitulosDetalle(parametros));
			logger.info("{}", titulos);
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}

		return TituloTranUtil.TituloBD2DTO(titulos);

	}

	public List<TituloTransaccionDTO> titulosEnLista(Long idLista, String prefix) throws ResultMapException, SQLException, TransaccionException {
		try {
			return TituloTranUtil.TituloBD2DTO(tituloDAO.obtenTitulos(null, Arrays.asList(idLista), prefix));
		} catch (PersistenceException e) {
			throw new TransaccionException("Error al cargar los datos.", e);
		} catch (DataAccessException e) {
			throw new TransaccionException("Error al cargar los datos", e);
		}
	}

	public boolean actualizarTituloEnmienda() {
		return false;
	}

	public TituloTransaccionDTO obtenerDatosComplementarios(Long idLista, Long idContrato,
			TituloTransaccionDTO titulo) {
		titulo.setIdLista(idLista);
		titulo.setIdContrato(idContrato);
		return titulo;
	}

	public void obtenerCatalogos(Long idContrato) {
		filiales = tituloDAO.obtenerFiliales(idContrato);
		categorias = tituloDAO.obtenerCategorias(idContrato);
		generosA = tituloDAO.obtenerGeneros();
		generosB = tituloDAO.obtenerGeneros();
		tiers = tituloDAO.obtenerTiers();
		catSeries = tituloDAO.obtenerCatSeries();
	}

	public List<CatalogoDTO> getFiliales() {
		return filiales;
	}

	public List<CatalogoDTO> getCategorias() {
		return categorias;
	}

	public List<CatalogoDTO> getGenerosA() {
		return generosA;
	}

	public List<CatalogoDTO> getGenerosB() {
		return generosB;
	}

	public List<CatalogoDTO> getTiers() {
		return tiers;
	}

	public List<CatalogoDTO> getCatSeries() {
		return catSeries;
	}
}