package br.com.elotech.websaude.integracao.esus.controller;

import br.com.elotech.websaude.integracao.esus.model.BD;
import br.com.elotech.websaude.integracao.esus.model.EsusHistoricoItens;
import br.com.elotech.websaude.integracao.esus.util.Compactador;
import br.ufsc.esus.dadoinstalacao.DadoInstalacaoTransport;
import br.ufsc.esus.dadotransporte.DadoTransporteTransportAtividadeColetivaXml;
import br.ufsc.esus.fichaatividadecoletiva.FichaAtividadeColetivaTransport;
import br.ufsc.esus.participanterowitem.ParticipanteRowItemTransport;
import br.ufsc.esus.profissionalcborowitem.ProfissionalCboRowItemTransport;
import br.ufsc.esus.unicalotacaoheader.UnicaLotacaoHeaderTransport;
import br.ufsc.esus.versao.VersaoTransport;
import org.apache.commons.lang3.StringUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static br.com.elotech.websaude.integracao.esus.util.DataConvert.dateToEpoch;

public class AtividadeColetiva extends BD {

  private static final Pattern REMOVE_TAGS = Pattern.compile("<.+?>");

  private static String stripTags(String string) {
    if (string == null || string.length() == 0) {
      return string;
    }

    Matcher m = REMOVE_TAGS.matcher(string);
    return m.replaceAll("");
  }

  public void executeMain(int eehCodigo, DadoInstalacaoTransport remetenteOriginadora)
    throws SQLException, JAXBException, IOException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    EsusHistoricoItens bdEsusHistoricoItens = new EsusHistoricoItens();
    ResultSet dadosAtividadeColetiva = bdAtividadeColetiva.getDadosAtividadeColetiva();

    while (dadosAtividadeColetiva.next()) {
      AtividadeColetiva atividadeColetiva = new AtividadeColetiva();
      String uuid = atividadeColetiva.getGUID();
      FichaAtividadeColetivaTransport fichaMaster = atividadeColetivaMasterThrift(uuid, dadosAtividadeColetiva);
      DadoTransporteTransportAtividadeColetivaXml arrayEnvio = montaArrayEnvioDto(fichaMaster, uuid,
        dadosAtividadeColetiva, eehCodigo, remetenteOriginadora);
      zipWriter(arrayEnvio, uuid);
      bdEsusHistoricoItens.registratHistoricoItens(eehCodigo, uuid, 6);
      bdAtividadeColetiva.atualizaStatus(uuid, dadosAtividadeColetiva.getInt("co_cds_ficha_ativ_col"));
    }
    dadosAtividadeColetiva.close();
  }

  private void zipWriter(DadoTransporteTransportAtividadeColetivaXml xmlText, String uuid)
    throws JAXBException, IOException {
    // Define nome do arquivo
    String arquivo = uuid + ".esus.xml";
    br.ufsc.esus.dadotransporte.ObjectFactoryAtividadeColetiva factoryCadastroIndividual = new br.ufsc.esus.dadotransporte.ObjectFactoryAtividadeColetiva();

    JAXBContext context;
    context = JAXBContext.newInstance(br.ufsc.esus.dadotransporte.ObjectFactoryAtividadeColetiva.class);
    JAXBElement<DadoTransporteTransportAtividadeColetivaXml> element
      = factoryCadastroIndividual.createDadoTransporteTransportAtividadeColetivaXml(xmlText);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
    marshaller.marshal(element, new FileWriter("arqs/" + arquivo));
    Compactador.ARQUIVOS.add(arquivo);

  }

  private FichaAtividadeColetivaTransport atividadeColetivaMasterThrift(String uuid, ResultSet row)
    throws SQLException {

    String outraLocalidade;
    Long inep;
    UnicaLotacaoHeaderTransport arrayUnica = montaArrayUnica(row);
    int codAtiv = row.getInt("co_cds_ficha_ativ_col");

    if (stripTags(row.getString("eav_local_atividade")) != null) {
      outraLocalidade = stripTags(row.getString("eav_local_atividade").trim());
      inep = null;
    } else {
      inep = row.getLong("eav_inep");
      outraLocalidade = null;
    }

    FichaAtividadeColetivaTransport dadosAct = new FichaAtividadeColetivaTransport();

    dadosAct.setHeaderTransport(arrayUnica);
    dadosAct.setUuidFicha(uuid);
    dadosAct.setOutraLocalidade(outraLocalidade);
    dadosAct.setInep(inep);
    dadosAct.setNumParticipantes(row.getInt("eav_num_participantes"));
    dadosAct.setNumAvaliacoesAlteradas(row.getInt("eav_num_aval_alteradas"));
    dadosAct.setAtividadeTipo(row.getLong("eav_atividade_tipo"));
    dadosAct.setTbCdsOrigem(3);
    dadosAct.setTurno((long) row.getInt("turno"));
    dadosAct.setPseEducacao(row.getBoolean("eav_educacao"));
    dadosAct.setPseSaude(row.getBoolean("eav_saude"));
    if (Boolean.FALSE.equals(dadosAct.getPseEducacao()) && Boolean.TRUE.equals(dadosAct.getPseSaude())) {
      dadosAct.getProfissionais().addAll(profissionalCboRowItemThrift(codAtiv));
    }
    dadosAct.getTemasParaReuniao().addAll(temasParaReuniao(codAtiv));
    dadosAct.getPublicoAlvo().addAll(publicoAlvo(codAtiv));
    dadosAct.getParticipantes().addAll(participantes(codAtiv));
    dadosAct.getPraticasEmSaude().addAll(praticasTemasParaSaude(codAtiv, "pratica"));
    dadosAct.getTemasParaSaude().addAll(praticasTemasParaSaude(codAtiv, "tema"));
    return dadosAct;
  }

  private UnicaLotacaoHeaderTransport montaArrayUnica(ResultSet row) throws SQLException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    ResultSet cbo = bdAtividadeColetiva.getCodCbo(row.getInt("co_cds_ficha_ativ_col"));

    UnicaLotacaoHeaderTransport headerTransport = new UnicaLotacaoHeaderTransport();
    headerTransport.setProfissionalCNS((validaCnsBanco(row.getString("eav_responsavel_cns").trim()) ?
      row.getString("eav_responsavel_cns").trim() :
      null));
    headerTransport.setCboCodigo2002((cbo.next() ? cbo.getString(1) : null));
    headerTransport.setCnes(StringUtils.leftPad(row.getString("eav_responsavel_cnes"), 7, "0"));
    headerTransport.setDataAtendimento(dateToEpoch(row.getDate("eav_dt_atividade")));
    headerTransport.setCodigoIbgeMunicipio(row.getString("eav_codigo_ibge"));
    headerTransport.setIne(row.getString("eav_responsavel_ine"));
    return headerTransport;
  }

  private List<ProfissionalCboRowItemTransport> profissionalCboRowItemThrift(int codAtiv) throws SQLException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    ResultSet dadosProfissional = bdAtividadeColetiva.getDadosProfissional(codAtiv);
    List<ProfissionalCboRowItemTransport> arrayGeral = new ArrayList<>();
    while (dadosProfissional.next()) {

      ProfissionalCboRowItemTransport array = new ProfissionalCboRowItemTransport();
      array.setCnsProfissional(validaCnsBanco(dadosProfissional.getString("cnes_cod_cns")) ?
        dadosProfissional.getString("cnes_cod_cns") :
        null);
      array.setCodigoCbo2002(dadosProfissional.getString("cbo"));

      arrayGeral.add(array);
    }
    dadosProfissional.close();
    return arrayGeral;
  }

  private List<Long> temasParaReuniao(int codAtiv) throws SQLException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    ResultSet dadosTemas = bdAtividadeColetiva.getCodigosTemas(codAtiv);
    List<Long> codsTema = new ArrayList<>();
    while (dadosTemas.next()) {
      codsTema.add(dadosTemas.getLong("co_cds_ativ_col_tema"));
    }
    dadosTemas.close();
    return codsTema;
  }

  private List<Long> publicoAlvo(int codAtiv) throws SQLException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    ResultSet dadosPublicoAlvo = bdAtividadeColetiva.getCodigosPublicoAlvo(codAtiv);
    List<Long> codsPublicoAlvo = new ArrayList<>();
    while (dadosPublicoAlvo.next()) {
      codsPublicoAlvo.add(dadosPublicoAlvo.getLong("co_cds_ativ_col_publico_alvo"));
    }
    dadosPublicoAlvo.close();
    return codsPublicoAlvo;
  }

  private List<Long> praticasTemasParaSaude(int codAtiv, String tipo) throws SQLException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    ResultSet dadosPratica = null;
    if (tipo.equals("pratica")) {
      dadosPratica = bdAtividadeColetiva.getCodigosPraticaPratica(codAtiv);
    }
    if (tipo.equals("tema")) {
      dadosPratica = bdAtividadeColetiva.getCodigosPraticaTema(codAtiv);
    }
    List<Long> codsPratica = new ArrayList<>();
    if (dadosPratica != null) {
      while (dadosPratica.next()) {
        codsPratica.add(dadosPratica.getLong("co_cds_ativ_col_pratica"));
      }
      dadosPratica.close();
    }
    return codsPratica;
  }

  private List<ParticipanteRowItemTransport> participantes(int codAtiv) throws SQLException {
    br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva bdAtividadeColetiva = new br.com.elotech.websaude.integracao.esus.model.AtividadeColetiva();
    ResultSet dadosParticipantes = bdAtividadeColetiva.getDadosParticipantes(codAtiv);
    List<ParticipanteRowItemTransport> arrayGeral = new ArrayList<>();
    while (dadosParticipantes.next()) {
      String usuCartaoSus = dadosParticipantes.getString("usu_cartao_sus").trim();
      if (validaCnsBanco(usuCartaoSus)) {
        long sexo = 4;
        if (dadosParticipantes.getString("usu_sexo").equals("M")) {
          sexo = 0;
        } else if (dadosParticipantes.getString("usu_sexo").equals("F")) {
          sexo = 1;
        }
        ParticipanteRowItemTransport array = new ParticipanteRowItemTransport();
        final Date dtNascimento = dadosParticipantes.getDate("dt_nascimento");
        array.setCnsParticipante(
          (validaCnsBanco(usuCartaoSus) ? dadosParticipantes.getString("usu_cartao_sus").trim() : null));
        if (array.getCnsParticipante() == null && validaCpf(dadosParticipantes.getString("usu_cpf"))) {
          array.setCpfParticipante(dadosParticipantes.getString("usu_cpf"));
        }
        if (dtNascimento != null)
          array.setDataNascimento(dateToEpoch(dtNascimento));
        array.setAvaliacaoAlterada(dadosParticipantes.getBoolean("st_avaliacao_alterada"));
        array.setPeso((dadosParticipantes.getDouble("nu_peso") < 1 ? 1.0 : dadosParticipantes.getDouble("nu_peso")));
        array.setAltura(
          (dadosParticipantes.getDouble("nu_altura") < 20 ? 20.0 : dadosParticipantes.getDouble("nu_altura")));
        array.setSexo(sexo);
        arrayGeral.add(array);
      }
    }
    dadosParticipantes.close();
    return arrayGeral;
  }

  private DadoTransporteTransportAtividadeColetivaXml montaArrayEnvioDto(
    FichaAtividadeColetivaTransport dadosAtividadeColetivaSerializado, String uuid, ResultSet row, int eehCodigo,
    DadoInstalacaoTransport remetenteOriginadora)
    throws SQLException {
    remetenteOriginadora.setUuidInstalacao(uuid);
    VersaoTransport arrayVersao = new VersaoTransport();
    arrayVersao.setMajor(3);
    arrayVersao.setMinor(2);
    arrayVersao.setRevision(4);

    DadoTransporteTransportAtividadeColetivaXml dadoTransporteTransportXml = new DadoTransporteTransportAtividadeColetivaXml();
    dadoTransporteTransportXml.setUuidDadoSerializado(uuid);
    dadoTransporteTransportXml.setTipoDadoSerializado(6);
    dadoTransporteTransportXml.setCnesDadoSerializado(
      row.getString("eav_uni_cnes") != null ? row.getString("eav_uni_cnes") : row.getString("eav_responsavel_cnes"));
    dadoTransporteTransportXml.setCnesDadoSerializado(StringUtils.leftPad(dadoTransporteTransportXml.getCnesDadoSerializado(), 7, "0"));
    dadoTransporteTransportXml.setCodIbge(row.getString("eav_codigo_ibge"));
    dadoTransporteTransportXml.setIneDadoSerializado(row.getString("eav_responsavel_ine"));
    dadoTransporteTransportXml.setNumLote(eehCodigo);
    dadoTransporteTransportXml.setRemetente(remetenteOriginadora);
    dadoTransporteTransportXml.setOriginadora(remetenteOriginadora);
    dadoTransporteTransportXml.setVersao(arrayVersao);
    dadoTransporteTransportXml.setFichaAtividadeColetivaTransport(dadosAtividadeColetivaSerializado);

    return dadoTransporteTransportXml;
  }
}
