package service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import model.ChequesEmitidos;
import model.ChequesPredatados;
import model.ContasPagar;
import model.ContasReceber;
import model.Fornecedor;
import model.LancaCaixa;
import model.PlanoContaGerencial;
import model.TipoDocumento;

import org.apache.commons.beanutils.BeanUtils;

import util.Assert;
import util.Constantes;
import util.DataUtils;
import util.Mensagens;
import dao.ChequesEmitidosDao;
import dao.ChequesPredatadosDao;
import dao.ContasPagarDao;
import dao.LancaCaixaDao;

public class ContasPagarService extends Service implements BO<ContasPagar> {
	
	@Inject
	private ContasPagarDao contasPagarDao;
	
	@Inject
	private LancaCaixaDao lancaCaixaDao;
	
	@Inject
	ChequesEmitidosDao chequesEmitidosDao;
	
	@Inject
	private MovCaixaFechamentoService mcfService;

	@Override
	public void salvar(ContasPagar entidade) throws ServiceException {
		// TODO Auto-generated method stub
		
	}
	
	public void alterar(TipoDocumento doc, PlanoContaGerencial conta, Fornecedor fornecedor, ContasPagar contaEdicao) throws ServiceException{
		try {
			
			if(validaEdicao(doc, conta, fornecedor, contaEdicao)){
				beginTransaction();
				ContasPagar contaPagar = contasPagarDao.carregar(contaEdicao.getContasPagarId(), ContasPagar.class);
				BeanUtils.copyProperties(contaPagar, contaEdicao);
				contaPagar.setTipoDocumentoId(doc);
				contaPagar.setPlanoContaGerencialId(conta);
				contaPagar.setFornecedorId(fornecedor);
				
				contasPagarDao.alterar(contaPagar);
				
				commitTransaction();
			}
			
		} catch (Exception e) {
			rollbackTransaction();
			throw new ServiceException(e.getMessage());
		}
	}

	@Override
	public void excluir(Long entidadeId) throws ServiceException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public List<ContasPagar> listar() throws ServiceException {
		// TODO Auto-generated method stub
		return null;
	}
	
	public void gerarConta(TipoDocumento doc, PlanoContaGerencial conta, Fornecedor fornecedor, String intervaloDia, Integer vencParcela, Date dataVenc1Parc,
			Integer qtdParcela, String nota, Double valorTotal, String tpGeracao) throws ServiceException{
		
		try {
			
			if(validarParametros(doc, conta, fornecedor, vencParcela, dataVenc1Parc, qtdParcela, nota, valorTotal)){
				
						
			beginTransaction();
			
			Double valorParcela = valorTotal / qtdParcela;
			for (int i = 0; i < qtdParcela; i++) {
				ContasPagar contasPagar = new ContasPagar();
				contasPagar.setTipoDocumentoId(doc);
				contasPagar.setPlanoContaGerencialId(conta);
				contasPagar.setFornecedorId(fornecedor);
				contasPagar.setNota(nota);
				contasPagar.setValorParcela(valorParcela);
				contasPagar.setTotalNota(valorTotal);
				contasPagar.setQtdParcela(qtdParcela);
				contasPagar.setNumeroParcela(i + 1);
				contasPagar.setStatusConta(Constantes.EM_ABERTO);
				contasPagar.setTpGeracao(tpGeracao);
				if(i == 0){
					contasPagar.setDataVencimento(dataVenc1Parc);
				}else{
					Calendar calendar = Calendar.getInstance();
					calendar.setTime(dataVenc1Parc);
					//intervalo em dias
					if(intervaloDia.equalsIgnoreCase("D")){
						calendar.add(Calendar.MONTH, i);
						calendar.set(Calendar.DAY_OF_MONTH, vencParcela);
						
					}else{
						
						calendar.add(Calendar.DAY_OF_MONTH, (vencParcela * i));
						
					}
					
					contasPagar.setDataVencimento(calendar.getTime());
					
				}
				contasPagarDao.salvar(contasPagar);
			}
			
			commitTransaction();
			
			}
			
		} catch (Exception e) {
			rollbackTransaction();
			throw new ServiceException(e.getMessage());
		}
	}
	
	public void pagar(ContasPagar conta, Double juros, Double desconto, Double valorPago, 
			Date dataPagamento, ChequesEmitidos cheque) throws ServiceException{
		
		try {
			
			//Validações
			if(dataPagamento == null){throw new ServiceException("Informe a data do Pagamento");}
			
			if(valorPago == null || valorPago.equals(0.0)){throw new ServiceException("Informe o valor Pago");}
			
				if(mcfService.caixaFechado(dataPagamento)){
					throw new ServiceException("Caixa do dia " + DataUtils.formataDataParaString(dataPagamento) + " Fechado!");
				}
				
				
				
				beginTransaction();
				
				if(conta.getTipoDocumentoId().getDescricao().equalsIgnoreCase("CHEQUE")){
					chequesEmitidosDao.salvar(cheque);
					conta.setChequesEmitidos(cheque);
				}
				
				conta.setDataBaixa(dataPagamento);
				conta.setJuros(juros);
				conta.setDesconto(desconto);
				conta.setValorPago(valorPago);
				conta.setStatusConta(Constantes.QUITADO);
				contasPagarDao.alterar(conta);
								
				if(!conta.getTipoDocumentoId().getDescricao().equalsIgnoreCase("CHEQUE")){
					//Efetuar Lança Caixa
					LancaCaixa lancaCaixa = new LancaCaixa();
					lancaCaixa.setDataEmissao(conta.getDataEmissao());
					lancaCaixa.setDataMovimento(dataPagamento);
					lancaCaixa.setNumeroDocumento(conta.getNota());
					lancaCaixa.setOrigemMovimento(Constantes.CONTAS_RECEBER);
					lancaCaixa.setParceiroId(conta.getFornecedorId().getFornecedorId());
					lancaCaixa.setTipoParceiro("F");
					lancaCaixa.setTpGeracao(Constantes.AUTOMATICO);
					lancaCaixa.setValor(valorPago);
					lancaCaixa.setSinal("S");
					lancaCaixa.setPlanoContaGerencialId(conta.getPlanoContaGerencialId());
					lancaCaixa.setTipoDocumentoId(conta.getTipoDocumentoId());
					
					lancaCaixaDao.salvar(lancaCaixa);
				}
						
				commitTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			throw new ServiceException(e.getMessage());
		}
	}
	
	public boolean validarParametros(TipoDocumento doc, PlanoContaGerencial conta, Fornecedor fornecedor, Integer vencParcela, Date dataVenc1Parc,
			Integer qtdParcela, String nota, Double valorTotal){
		
		Assert.notNull(doc, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(conta, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(fornecedor, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(dataVenc1Parc, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(valorTotal, Mensagens.MSG_CAMPO_OBRIGATORIO);
		
		if(qtdParcela > 1){
			Assert.notNull(vencParcela, "O vencimento das parcelas deve ser informado.");
			Assert.isTrue(vencParcela > 0, "Vencimento das parcelas deve ser maior de 0");
		}
		
		Assert.isTrue(valorTotal > 0.0, "O valor total deve ser maior que 0.0");
		
		Assert.isTrue(conta.getTipoMovimento().equalsIgnoreCase("RECEITA"), "Conta Gerencial não pode ser 'Despesa'");
		
		
		return true;
	}
	
	public List<ContasPagar> listarParametros(Date dataIni, Date dataFim, Long fornecedorId, String status) throws ServiceException {
		try {
			String ordem = "dataVencimento";
			Map<String, Object> filtros = new HashMap<String, Object>();
			filtros.put("dataVencimento >=", dataIni);
			filtros.put("dataVencimento <=", dataFim);
			filtros.put("fornecedorId join", fornecedorId);
			if(!status.equalsIgnoreCase(Constantes.TODOS)){
				filtros.put("statusConta", status);
			}

			List<ContasPagar> list = new ArrayList<ContasPagar>();
			list = contasPagarDao.listar(filtros, ordem, 0);
			
			return list;
			
		} catch (Exception e) {
			throw new ServiceException(e.getMessage());
		}
	}
	
public boolean validaEdicao(TipoDocumento doc, PlanoContaGerencial conta, Fornecedor fornecedor, ContasPagar contaEdicao){
		
		Assert.notNull(doc, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(conta, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(fornecedor, Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(contaEdicao.getDataVencimento(), Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.notNull(contaEdicao.getValorParcela(), Mensagens.MSG_CAMPO_OBRIGATORIO);
		Assert.isTrue(contaEdicao.getValorParcela() > 0.0, "O valor parcela deve ser maior que 0.0");
		Assert.isTrue(conta.getTipoMovimento().equalsIgnoreCase("DESPESA"), "Conta Gerencial não pode ser 'Receita'");
		
		return true;
	}

	@Override
	public boolean validar(ContasPagar entidade) {
		// TODO Auto-generated method stub
		return false;
	}

}
