package br.com.centralit.bpm.integracao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import br.com.centralit.bpm.dto.AtribuicaoFluxoDTO;
import br.com.centralit.bpm.dto.GrupoBpmDTO;
import br.com.centralit.bpm.util.Enumerated;
import br.com.centralit.bpm.util.Enumerated.AssignmentType;
import br.com.centralit.bpm.util.Enumerated.StatusWorkItem;
import br.com.centralit.citcorpore.bean.GrupoDTO;
import br.com.citframework.dto.IDto;
import br.com.citframework.excecao.PersistenceException;
import br.com.citframework.integracao.Condition;
import br.com.citframework.integracao.CrudDaoDefaultImpl;
import br.com.citframework.integracao.Field;
import br.com.citframework.integracao.Order;
import br.com.citframework.util.Constantes;

public class AtribuicaoFluxoDao extends CrudDaoDefaultImpl {

    private static final String TABLE_NAME = "bpm_atribuicaofluxo";

	private static final String SQL_RESTORE = "SELECT A.idAtribuicao, A.idItemTrabalho, A.idType, A.idUsuario, A.idGrupo, A.dataHora FROM Bpm_AtribuicaoFluxo A INNER JOIN Bpm_ItemTrabalhoFluxo I ON A.idItemTrabalho = I.idItemTrabalho ";

	private static final String SQL_RESTORE_ALL = "SELECT A.idAtribuicao, A.idItemTrabalho, A.idType, A.idUsuario, A.idGrupo, A.dataHora, E.documentacao, E.nome, U.login, G.sigla, I.idStatus, E.idElemento"
												+ "  FROM Bpm_AtribuicaoFluxo A INNER JOIN Bpm_ItemTrabalhoFluxo I ON A.idItemTrabalho = I.idItemTrabalho "
												+ "  							INNER JOIN Bpm_ElementoFluxo E ON I.idElemento = E.idElemento "
												+ "  							 LEFT JOIN Grupo G ON G.idGrupo = A.idGrupo "
												+ "  							 LEFT JOIN Usuario U ON U.idUsuario = A.idUsuario ";

    public AtribuicaoFluxoDao() {
        super(Constantes.getValue("DATABASE_ALIAS"), null);
    }

	@Override
	public IDto create(IDto obj) throws PersistenceException {
		return super.create(obj);
	}

    private List<String> getListaDeCampos() {
        final List<String> listRetorno = new ArrayList<>();
        listRetorno.add("idAtribuicao");
        listRetorno.add("idItemTrabalho");
		listRetorno.add("idType");
        listRetorno.add("idUsuario");
        listRetorno.add("idGrupo");
        listRetorno.add("dataHora");
        return listRetorno;
    }

    @Override
    public Collection<Field> getFields() {
        final Collection<Field> listFields = new ArrayList<>();
        listFields.add(new Field("idAtribuicao", "idAtribuicao", true, true, false, false));
        listFields.add(new Field("idItemTrabalho", "idItemTrabalho", false, false, false, false));
		listFields.add(new Field("idType", "idType", false, false, false, false));
        listFields.add(new Field("idUsuario", "idUsuario", false, false, false, false));
        listFields.add(new Field("idGrupo", "idGrupo", false, false, false, false));
        listFields.add(new Field("dataHora", "dataHora", false, false, false, false));
        return listFields;
    }

    @Override
    public String getTableName() {
        return TABLE_NAME;
    }

    @Override
    public Collection<AtribuicaoFluxoDTO> list() throws PersistenceException {
        return null;
    }

    @Override
    public Class<AtribuicaoFluxoDTO> getBean() {
        return AtribuicaoFluxoDTO.class;
    }

    @Override
    public Collection<AtribuicaoFluxoDTO> find(final IDto arg0) throws PersistenceException {
        return null;
    }

    public Collection<AtribuicaoFluxoDTO> findDisponiveis(final Integer idUsuario, final Collection<GrupoBpmDTO> grupos) throws PersistenceException {
		String sql = SQL_RESTORE + " WHERE I.idStatus <> ? AND I.idStatus <> ? AND (A.idUsuario = ? ";
        if (grupos != null && !grupos.isEmpty()) {
            sql += " OR A.idGrupo IN (";
            int i = 0;
            for (final GrupoBpmDTO grupoBpmDto : grupos) {
                if (i > 0) {
                    sql += ",";
                }
                sql += grupoBpmDto.getIdGrupo();
                i++;
            }
            sql += ") ";
        }
        sql += " OR I.idResponsavelAtual = ? )";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idUsuario, idUsuario });

        return engine.listConvertion(this.getBean(), lista, this.getListaDeCampos());
    }

    public Collection<AtribuicaoFluxoDTO> findDisponiveisByIdUsuario(final Integer idUsuario) throws PersistenceException {
		final String sql = SQL_RESTORE + " WHERE I.idStatus <> ? AND I.idStatus <> ? AND A.idUsuario = ? ORDER BY A.dataHora";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idUsuario });

        return engine.listConvertion(this.getBean(), lista, this.getListaDeCampos());
    }

    public Collection<AtribuicaoFluxoDTO> findDisponiveisByIdGrupo(final Integer idGrupo) throws Exception {
		final String sql = SQL_RESTORE + " WHERE I.idStatus <> ? AND I.idStatus <> ?  AND idGrupo = ? ORDER BY A.dataHora";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idGrupo });

        return engine.listConvertion(this.getBean(), lista, this.getListaDeCampos());
    }

    public Collection<AtribuicaoFluxoDTO> findByDisponiveisByIdInstancia(final Integer idInstancia) throws PersistenceException {
		final String sql = SQL_RESTORE + " WHERE I.idStatus <> ? AND I.idStatus <> ? AND I.idInstancia = ? ORDER BY A.dataHora";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idInstancia });

        return engine.listConvertion(this.getBean(), lista, this.getListaDeCampos());
    }

    public Collection<AtribuicaoFluxoDTO> findDisponiveisByIdInstancia(final Integer idInstancia) throws PersistenceException {
		final String sql = SQL_RESTORE_ALL + " WHERE I.idStatus <> ? AND I.idStatus <> ? AND I.idInstancia = ? AND (A.idGrupo IS NOT NULL OR A.idUsuario IS NOT NULL) ORDER BY A.dataHora";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idInstancia });

        List<String> listaDeCampos = this.getListaDeCampos();
		listaDeCampos.add("documentacao");
        listaDeCampos.add("descricao");
        listaDeCampos.add("usuario");
        listaDeCampos.add("grupo");
		listaDeCampos.add("idStatus");
        listaDeCampos.add("idElemento");

        return engine.listConvertion(this.getBean(), lista, listaDeCampos);
    }

    public Collection<AtribuicaoFluxoDTO> findByDisponiveisByIdItemTrabalho(final Integer idItemTrabalho) throws PersistenceException {
		final String sql = SQL_RESTORE + " WHERE I.idStatus <> ? AND I.idStatus <> ? AND I.idItemTrabalho = ? ORDER BY A.dataHora";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idItemTrabalho });

        return engine.listConvertion(this.getBean(), lista, this.getListaDeCampos());
    }

    public Collection<AtribuicaoFluxoDTO> findByIdUsuario(final Integer idUsuario) throws PersistenceException {
        final List<Condition> condicao = new ArrayList<>();
        final List<Order> ordenacao = new ArrayList<>();
        condicao.add(new Condition("idUsuario", "=", idUsuario));
        ordenacao.add(new Order("idAtribuicao"));
        return super.findByCondition(condicao, ordenacao);
    }

    public Collection<AtribuicaoFluxoDTO> findByIdGrupo(final Integer idGrupo) throws PersistenceException {
        final List<Condition> condicao = new ArrayList<>();
        final List<Order> ordenacao = new ArrayList<>();
        condicao.add(new Condition("idGrupo", "=", idGrupo));
        ordenacao.add(new Order("idAtribuicao"));
        return super.findByCondition(condicao, ordenacao);
    }

	public Collection<AtribuicaoFluxoDTO> findByIdItemTrabalhoAndTipo(final Integer idItemTrabalho, final Integer idType) throws PersistenceException {
        final List<Condition> condicao = new ArrayList<>();
        final List<Order> ordenacao = new ArrayList<>();
		condicao.add(new Condition("idItemTrabalho", idItemTrabalho));
		condicao.add(new Condition("idType", idType));
        ordenacao.add(new Order("idAtribuicao"));
        return super.findByCondition(condicao, ordenacao);
    }

    public Collection<AtribuicaoFluxoDTO> findByIdItemTrabalhoAndIdUsuario(final Integer idItemTrabalho, final Integer idUsuario, final AssignmentType tipo)
            throws PersistenceException {
        final List<Condition> condicao = new ArrayList<>();
        final List<Order> ordenacao = new ArrayList<>();
		condicao.add(new Condition("idItemTrabalho", idItemTrabalho));
		condicao.add(new Condition("idType", tipo.getId()));
		condicao.add(new Condition("idUsuario", idUsuario));
        ordenacao.add(new Order("idAtribuicao"));
        return super.findByCondition(condicao, ordenacao);
    }

    public void deleteDelegacao(final Integer idItemTrabalho) throws PersistenceException {
        final List<Condition> condicao = new ArrayList<>();
		condicao.add(new Condition("idItemTrabalho", idItemTrabalho));
		condicao.add(new Condition("idType", AssignmentType.DELEGATION.getId()));
        super.deleteByCondition(condicao);
    }

    /**
	 *
	 * Consulta na tabela a existencia de registros cadastrados com os itens do parametro
	 *
	 * @param idItemTrabalho
	 * @param idUsuario
	 * @param idType
	 * @return
	 * @throws PersistenceException
	 */
	public Collection<AtribuicaoFluxoDTO> findByIdItemTrabalhoAndIdUsuarioAndTipo(final Integer idItemTrabalho, final Integer idUsuario, final Integer idType)
            throws PersistenceException {
        final List<Condition> condicao = new ArrayList<>();
		condicao.add(new Condition("idItemTrabalho", idItemTrabalho));
		condicao.add(new Condition("idUsuario", idUsuario));
		condicao.add(new Condition("idType", idType));

        final List<Order> ordenacao = new ArrayList<>();
        ordenacao.add(new Order("idAtribuicao"));

        return super.findByCondition(condicao, ordenacao);
    }

    public Collection<AtribuicaoFluxoDTO> findByDisponiveisByIdInstanciaAndIdUsuario(final Integer idInstancia, final Integer idUsuario) throws PersistenceException {
		final String sql = SQL_RESTORE + " WHERE I.idStatus <> ? AND I.idStatus <> ? AND I.idInstancia = ? AND A.idUsuario = ? ORDER BY A.dataHora";

		final List<?> lista = this.execSQL(sql, new Object[] { StatusWorkItem.EXECUTED.getId(), StatusWorkItem.CANCELED.getId(), idInstancia, idUsuario });

        return engine.listConvertion(this.getBean(), lista, this.getListaDeCampos());
    }

	/**
	 * Retorna o grupo da tarefa atual com permissão de delegar, executar, reativar e suspender
	 * 
	 * @author gilmar.junior
	 * @since 22.12.2016
	 * @param idItemTrabalho
	 * @param idType
	 * @return String
	 * @throws PersistenceException
	 **/
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public String getNomeGrupoTarefaAtual(Integer idItemTrabalho, Integer idType) throws PersistenceException {
		StringBuilder sql = new StringBuilder();
		List parameters = new ArrayList();
		List result = new ArrayList();
		List field = new ArrayList();
		String grupoTarefaAtual = "";

		if(idItemTrabalho != null && idType != null){
			sql.append("SELECT ").append(" g.sigla \n");
			sql.append(" FROM ").append(this.getTableName()).append(" af \n");
			sql.append(" INNER JOIN grupo g ON g.idgrupo = af.idgrupo \n");

			sql.append(" WHERE af.iditemtrabalho = ? ");
			parameters.add(idItemTrabalho);

			if (idType.equals(Enumerated.AssignmentType.MONITORING.getId())) {
				sql.append(" AND af.idtype <> ? \n");
				parameters.add(idType);
			} else {
				sql.append(" AND af.idtype = ? \n");
				parameters.add(idType);
			}

			sql.append(" AND af.idgrupo IS NOT NULL \n");
			sql.append(" ORDER BY af.datahora DESC \n");

			result = this.execSQL(sql.toString(), parameters.toArray());

			field.add("sigla");
			List<GrupoDTO> retorno = listConvertion(GrupoDTO.class, result, field);

			if (retorno != null && !retorno.isEmpty()) {
				grupoTarefaAtual = retorno.get(0).getSigla();
			}
		}

		return grupoTarefaAtual;
	}
}
