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

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.mx.dla.dda.contrato.fees.daos.FeesContratoDAO;
import com.mx.dla.dda.contrato.transaccion.catalagos.dtos.TipoCambioTDTO;
import com.mx.dla.dda.contrato.transaccion.exceptions.dtos.TransaccionException;
import com.mx.dla.dda.contrato.transaccion.fees.daos.FeesTransaccionDAO;
import com.mx.dla.dda.contrato.transaccion.fees.dtos.FeesEstDTO;
import com.mx.dla.dda.contrato.transaccion.fees.dtos.FeesLibreriaDTO;
import com.mx.dla.dda.contrato.transaccion.fees.dtos.FeesPremierDTO;
import com.mx.dla.dda.contrato.transaccion.fees.dtos.FeesTransaccionDTO;
import com.mx.dla.dda.excelMapper.bos.ExcelMapperTransform;
import com.mx.dla.dda.excelMapper.constants.ExcelMapperDataType;
import com.mx.dla.dda.excelMapper.dtos.ExcelEntityResult;
import com.mx.dla.dda.excelMapper.dtos.ExcelMapper;
import com.mx.dla.dda.excelMapper.dtos.ExcelRule;
import com.mx.dla.dda.excelMapper.exceptions.ExcelMapperException;
import com.mx.dla.global.bos.BaseBO;
import com.mx.dla.global.dtos.FilaExcelDTO;

@Service
public class FeesTransaccioBO extends BaseBO{

	@Autowired
	private FeesPremierTransaccioBO premier;
	
	@Autowired
	private FeesLibreriaTransaccioBO feesLib;
	
	@Autowired
	private FeesEstTransaccioBO feesEst;

	@Autowired
	private FeesContratoDAO     feesContratoDAO;
	
	@Autowired
	private FeesTransaccionDAO  feesTDAO;
	
	@Autowired
	private ExcelMapperTransform excelTransform;

	@Value("${uri.file.carga.fees}")
	protected String uriCarga;

	private String fechaInicio;
	private String fechaFin   ;
	private String nombreArchivo;
	
	public FeesTransaccionDTO obtenerFees(Long idContrato){
		
		FeesTransaccionDTO fees = new FeesTransaccionDTO();

		this.fechaInicio = feesContratoDAO.fechaInicio(idContrato);
		this.fechaFin    = feesContratoDAO.fechaFin   (idContrato);
		
		fees.setFechaInicioCto(this.fechaInicio);
		fees.setFechaFinCto(this.fechaFin);
		
		fees = this.obtenerTiposCambio(fees);
				
		Long tipo = 0l;
		fees.setIdTipoCambio(tipo.longValue());		
										
		return fees;
	}
	
	private FeesTransaccionDTO  obtenerTiposCambio(FeesTransaccionDTO fees){
		List<TipoCambioTDTO> tipos = new ArrayList<TipoCambioTDTO>();

		TipoCambioTDTO t = new TipoCambioTDTO();
		t.setId(0l);
		t.setDesc("Selecciona Valor");
		tipos.add(t);
		
		tipos.addAll(feesTDAO.getTipoCambio());
		fees.setTiposCambio(tipos);
		return fees;
	}
	
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void guardarFees(String tipo, Long idContrato, Long idTipoCambio, FeesPremierDTO feesPremierDTO, FeesLibreriaDTO feesLibreriaDTO, FeesEstDTO  feesEstDTO) throws ResultMapException, SQLException, TransaccionException{		
		try
		{
			if(idTipoCambio != null)
			{
				feesTDAO.eliminarTipoCambio(idContrato);
				feesTDAO.guardarTipoCambio(idContrato, idTipoCambio);	
			}
				
			if(tipo.compareTo("Premier")== 0)
			{
				logger.debug(feesPremierDTO.toString());
				premier.guardarFeesTransaccion(idContrato, null, null, feesPremierDTO);
			}
			else if(tipo.compareTo("Libreria")== 0)
			{
				logger.debug(feesLibreriaDTO.toString());
				feesLib.guardarFeesLibreria(idContrato, null, null, feesLibreriaDTO);
			}
			else if(tipo.compareTo("Est")== 0)
			{
				logger.debug(feesEst.toString());
				feesEst.guardarFeesEst(idContrato, null, null, feesEstDTO);
			}
		} catch (PersistenceException e) {
			throw new TransaccionException("Se genero un error al guardar los datos.",e);
        } catch (DataAccessException e) {
        	throw new TransaccionException("Se genero un error al guardar los datos.",e);
        }	
	}
	
	public FeesPremierDTO obtenerPremierFees(Long idContrato) throws ResultMapException, SQLException, TransaccionException{
		
		this.fechaInicio = feesContratoDAO.fechaInicio(idContrato);
		this.fechaFin    = feesContratoDAO.fechaFin   (idContrato);
		return premier.obtenerFeesTransaccion(idContrato, this.fechaInicio, this.fechaFin);					
	}
	
	public FeesLibreriaDTO obtenerLibreriaFees(Long idContrato) throws ResultMapException, SQLException, TransaccionException{
		
		this.fechaInicio = feesContratoDAO.fechaInicio(idContrato);
		this.fechaFin    = feesContratoDAO.fechaFin   (idContrato);
		return feesLib.obtenerFeesLibreria(idContrato, this.fechaInicio, this.fechaFin);	
	}

	public FeesEstDTO obtenerEstFees(Long idContrato) throws ResultMapException, SQLException, TransaccionException{
		
		this.fechaInicio = feesContratoDAO.fechaInicio(idContrato);
		this.fechaFin    = feesContratoDAO.fechaFin   (idContrato);
		return feesEst.obtenerFeesEst(idContrato, this.fechaInicio, this.fechaFin);
	}
	
	public boolean verificarCategoria(Long id) throws ResultMapException, SQLException, TransaccionException{		
		try
		{
			return true;
		} catch (PersistenceException e) {
			throw new TransaccionException("Se genero un error al guardar los datos.",e);
        } catch (DataAccessException e) {
        	throw new TransaccionException("Se genero un error al guardar los datos.",e);
        }		
	}
	
	public byte[] descargarArchivoExcel(String seccion, String operacion, List<List<String>> datos, List<String> encabezados) throws ResultMapException, SQLException, TransaccionException{
		byte[] archivo = null;
		
		try
		{
			if(seccion.compareTo("premier") == 0)
			{
				switch(operacion){
					case "min_cat":
						nombreArchivo = "templateFees/dda_premierMGC_";						
					break;
					case "min_anio":
						nombreArchivo = "templateFees/dda_premierMGA_";																		
					break;
					case "release":
						nombreArchivo = "templateFees/dda_premierRD_";						
					break;
					case "precio":
						nombreArchivo = "templateFees/dda_premierPPE_";						
					break;				
				}
				
				if(datos == null)													
					archivo = this.getFile(nombreArchivo+".xlsx");							
				else						
					archivo = excelTransform.transformMapToExcel2(datos,encabezados);
			}
			else if(seccion.compareTo("libreria") == 0)
			{
				switch(operacion)
				{
					case "min_cat":
						nombreArchivo = "templateFees/dda_libreriaMG_";						
					break;
					case "min_anio":
						nombreArchivo = "templateFees/dda_libreriaMGA_";																		
					break;
					case "precio":
						nombreArchivo = "templateFees/dda_libreriaPPE_";						
					break;				
				}
			
				if(datos == null)													
					archivo = this.getFile(nombreArchivo+".xlsx");							
				else						
					archivo = excelTransform.transformMapToExcel2(datos,encabezados);
				
			}
			else if(seccion.compareTo("est") == 0)
			{
				switch(operacion)
				{
					case "min_cat":
						nombreArchivo = "templateFees/dda_ventaMG_";						
					break;
					case "min_anio":
						nombreArchivo = "templateFees/dda_ventaMGA_";																		
					break;
					case "precio movies":
						nombreArchivo = "templateFees/dda_ventaMoviesPPE_";						
					break;
					case "precio series":
						nombreArchivo = "templateFees/dda_ventaSeriesPPE_";						
					break;
				}
			
				if(datos == null)													
					archivo = this.getFile(nombreArchivo+".xlsx");							
				else						
					archivo = excelTransform.transformMapToExcel2(datos,encabezados);
			}			
			return archivo;
			
		} catch (PersistenceException e) {
			throw new TransaccionException("Se genero un error al descargar el arhivo.", e);
        } catch (DataAccessException e) {
        	throw new TransaccionException("Se genero un error al descargar el arhivo.", e);
        } catch (ExcelMapperException e) {
        	throw new TransaccionException("Se genero un error al descargar el arhivo.", e);
		} catch (IOException e) {
			throw new TransaccionException("Se genero un error al descargar el arhivo.", e);
		}
	}
		
	private byte[] getFile(String fileName) throws IOException{				  		
		  ClassLoader classLoader = getClass().getClassLoader();		  		  
		  InputStream stream = classLoader.getResourceAsStream(fileName);		  
		  byte[] byteArr = IOUtils.toByteArray(stream);
		  return byteArr;			  
	}
	
	public List<FilaExcelDTO> obtenerDatosExcel(File fileUpload, String fileName, String expediente, Long idContrato ) throws IOException, ExcelMapperException{		
		String nombreArchivo = uriCarga + idContrato + expediente + fileName;
		byte [] f = FileUtils.readFileToByteArray(fileUpload);
		File d    = new File(nombreArchivo);
		
		d.setExecutable(true, false);
		d.setReadable(true, false);
		d.setWritable(true, false);
		
		logger.debug("Absolute path [{}]  -  [{}]",d.getCanonicalPath() , d.getPath());
		FileUtils.writeByteArrayToFile(d, f);		
		
		List<FilaExcelDTO>datos = this.obtenerDatosExcel(nombreArchivo);
		
		FileUtils.deleteQuietly(d);
		logger.debug(datos.toString());
		return datos;	
	}

	public List<FilaExcelDTO> obtenerDatosExcel(String nombreArchivo) throws ExcelMapperException{
		   List<FilaExcelDTO> datos = new ArrayList<FilaExcelDTO>();

		   ExcelMapper mapper = new ExcelMapper();
		   mapper.setClassName("com.mx.dla.global.dtos.FilaExcelDTO");
		   mapper.setFirstRow(1);
			
		   List<ExcelRule> rules = new ArrayList<ExcelRule>();
		   ExcelRule er = new ExcelRule();
		   
		   er.setType(ExcelMapperDataType.string);			
		   er.setAttribute("fila");
		   rules.add(er);
		   
		   mapper.setRules(rules);			
						
		   ExcelEntityResult<Object> res = excelTransform.readExcelToObject(nombreArchivo, mapper);					   
		   
		   for(int i=0; i<res.getResult().size(); i++)
		   {
			   FilaExcelDTO fila = (FilaExcelDTO)res.getResult().get(i);
			  datos.add(fila);			  
		   }
		   
		   return datos;
	}
	
	public String getNombreArchivo() {
		return nombreArchivo;
	}
	
	
}