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.BancoFichaAtendimentoDomiciliar;
import br.com.elotech.websaude.integracao.esus.model.EsusHistoricoItens;
import br.com.elotech.websaude.integracao.esus.model.enums.TipoDadoSerializado;
import br.com.elotech.websaude.integracao.esus.util.Compactador;
import br.ufsc.esus.dadoinstalacao.DadoInstalacaoTransport;
import br.ufsc.esus.dadotransporte.DadoTransporteTransportAvaliacaoElegibilidadeXml;
import br.ufsc.esus.dadotransporte.DadoTransporteTransportFichaAtendimentoDomiciliarXml;
import br.ufsc.esus.dadotransporte.ObjectFactoryAvaliacaoElegibilidade;
import br.ufsc.esus.dadotransporte.ObjectFactoryFichaAtendimentoDomiciliar;
import br.ufsc.esus.fichaatendimentodomiciliarchild.FichaAtendimentoDomiciliarChildTransport;
import br.ufsc.esus.fichaatendimentodomiciliarmaster.FichaAtendimentoDomiciliarMasterTransport;
import br.ufsc.esus.lotacaoheader.LotacaoHeaderTransport;
import br.ufsc.esus.variaslotacoesheader.VariasLotacoesHeaderTransport;
import br.ufsc.esus.versao.VersaoTransport;

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.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import static br.com.elotech.websaude.integracao.esus.util.DataConvert.dateToEpoch;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.leftPad;

public class FichaAtendimentoDomicilar extends BD {

  BancoFichaAtendimentoDomiciliar bancoFichaAtendimentoDomiciliar = new BancoFichaAtendimentoDomiciliar();
  private String ineProfissionalPrincipal;

  public void executeMain(int eehCodigo, DadoInstalacaoTransport remetenteOriginadora) throws SQLException, JAXBException, IOException {
    EsusHistoricoItens bdEsusHistoricoItens = new EsusHistoricoItens();
    ResultSet dadosAtendimentoDomiciliar = bancoFichaAtendimentoDomiciliar.getDados();

    while (dadosAtendimentoDomiciliar.next()) {
      String uuid = getGUID();
      FichaAtendimentoDomiciliarMasterTransport transport = gerarFichaAtendimentoDomiciliarMasterTransport(uuid, dadosAtendimentoDomiciliar);
      DadoTransporteTransportFichaAtendimentoDomiciliarXml arrayEnvio = montaArrayEnvioDto(transport, uuid, dadosAtendimentoDomiciliar, eehCodigo, remetenteOriginadora);
      zipWriter(arrayEnvio, uuid);
      bdEsusHistoricoItens.registratHistoricoItens(eehCodigo, uuid, 11);
      bancoFichaAtendimentoDomiciliar.atualizaStatus(uuid, dadosAtendimentoDomiciliar.getInt("ade_id"));
    }

    dadosAtendimentoDomiciliar.close();
  }

  private void zipWriter(DadoTransporteTransportFichaAtendimentoDomiciliarXml xml, String uuid)
    throws JAXBException, IOException {
    String arquivo = uuid + ".esus.xml";
    ObjectFactoryFichaAtendimentoDomiciliar factoryFichaAtendimentoDomiciliar = new ObjectFactoryFichaAtendimentoDomiciliar();
    JAXBContext context = JAXBContext.newInstance(ObjectFactoryFichaAtendimentoDomiciliar.class);
    JAXBElement<DadoTransporteTransportFichaAtendimentoDomiciliarXml> element = factoryFichaAtendimentoDomiciliar.createDadoTransporteTransportFichaAtendimentoDomiciliarXml(xml);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
    marshaller.marshal(element, new FileWriter("arqs/" + arquivo));
    Compactador.ARQUIVOS.add(arquivo);
  }

  private FichaAtendimentoDomiciliarMasterTransport gerarFichaAtendimentoDomiciliarMasterTransport(String uuid, ResultSet dadosAtendimentoDomiciliar) throws SQLException {
    FichaAtendimentoDomiciliarMasterTransport fichaAtendimentoDomiciliarMasterTransport = new FichaAtendimentoDomiciliarMasterTransport();

    fichaAtendimentoDomiciliarMasterTransport.setUuidFicha(uuid);
    fichaAtendimentoDomiciliarMasterTransport.setTpCdsOrigem(3);
    fichaAtendimentoDomiciliarMasterTransport.setHeaderTransport(gerarVariasLotacoesHeaderTransport(dadosAtendimentoDomiciliar));

    resolveAtendimentosDomiciliaresChild(fichaAtendimentoDomiciliarMasterTransport, dadosAtendimentoDomiciliar.getLong("ate_codigo"));

    return fichaAtendimentoDomiciliarMasterTransport;
  }

  private VariasLotacoesHeaderTransport gerarVariasLotacoesHeaderTransport(ResultSet rs) throws SQLException {
    VariasLotacoesHeaderTransport headerTransport = new VariasLotacoesHeaderTransport();

    headerTransport.setLotacaoFormPrincipal(gerarLotacaoFormPrincipal(rs));
    if ("S".equalsIgnoreCase(rs.getString("ate_compartilhado"))) {
      headerTransport.setLotacaoFormAtendimentoCompartilhado(gerarLotacaoFormAtendimentoCompartilhado(rs));
    }

    headerTransport.setDataAtendimento(dateToEpoch(rs.getDate("ate_data")));
    headerTransport.setCodigoIbgeMunicipio(rs.getString("ibge_unidade"));

    return headerTransport;
  }

  private LotacaoHeaderTransport gerarLotacaoFormPrincipal(ResultSet rs) throws SQLException {
    LotacaoHeaderTransport lotacaoHeaderTransport = new LotacaoHeaderTransport();

    ResultSet rsProfissional = bancoFichaAtendimentoDomiciliar.getProfissionalPrincipal(rs.getLong("ade_id"));
    if (rsProfissional.next()) {
      lotacaoHeaderTransport.setProfissionalCNS(rsProfissional.getString("cns"));
      lotacaoHeaderTransport.setCboCodigo2002(rsProfissional.getString("cbo"));
      lotacaoHeaderTransport.setCnes(rsProfissional.getString("cnes"));
      lotacaoHeaderTransport.setIne(rsProfissional.getString("ine"));
      ineProfissionalPrincipal = rsProfissional.getString("ine");
    }
    rsProfissional.close();
    return lotacaoHeaderTransport;
  }

  private LotacaoHeaderTransport gerarLotacaoFormAtendimentoCompartilhado(ResultSet rs) throws SQLException {
    LotacaoHeaderTransport lotacaoHeaderTransport = new LotacaoHeaderTransport();

    ResultSet rsProfissional = bancoFichaAtendimentoDomiciliar.getProfissionalAuxiliar(rs.getLong("ade_id"));
    if (rsProfissional.next()) {
      lotacaoHeaderTransport.setProfissionalCNS(rsProfissional.getString("cns"));
      lotacaoHeaderTransport.setCboCodigo2002(rsProfissional.getString("cbo"));
      lotacaoHeaderTransport.setCnes(rsProfissional.getString("cnes"));
      lotacaoHeaderTransport.setIne(rsProfissional.getString("ine"));
    }
    rsProfissional.close();
    return lotacaoHeaderTransport;
  }

  private DadoTransporteTransportFichaAtendimentoDomiciliarXml montaArrayEnvioDto(
    FichaAtendimentoDomiciliarMasterTransport transport, String uuid, ResultSet dadosAtendimentoDomiciliar,
    int eehCodigo, DadoInstalacaoTransport remetenteOriginadora) throws SQLException {
    VersaoTransport versaoTransport = new VersaoTransport(3, 2, 4);

    DadoTransporteTransportFichaAtendimentoDomiciliarXml dadoTransporteTransportXml = new DadoTransporteTransportFichaAtendimentoDomiciliarXml();
    dadoTransporteTransportXml.setUuidDadoSerializado(uuid);
    dadoTransporteTransportXml.setTipoDadoSerializado(TipoDadoSerializado.ATENDIMENTODOMICILIAR.getValue());
    dadoTransporteTransportXml.setCnesDadoSerializado(leftPad(dadosAtendimentoDomiciliar.getString("cnes"), 7, "0"));
    dadoTransporteTransportXml.setCodIbge(dadosAtendimentoDomiciliar.getString("ibge_unidade"));
    dadoTransporteTransportXml.setNumLote(eehCodigo);
    dadoTransporteTransportXml.setIneDadoSerializado(ineProfissionalPrincipal);
    dadoTransporteTransportXml.setRemetente(remetenteOriginadora);
    dadoTransporteTransportXml.setOriginadora(remetenteOriginadora);
    dadoTransporteTransportXml.setVersao(versaoTransport);
    dadoTransporteTransportXml.setFichaAtendimentoDomiciliarMasterTransport(transport);
    return dadoTransporteTransportXml;
  }

  private void resolveAtendimentosDomiciliaresChild(FichaAtendimentoDomiciliarMasterTransport fichaTransport, Long codigoAtendimento) throws SQLException {
    ResultSet rs = bancoFichaAtendimentoDomiciliar.getDadosAtendimentoDomiciliarChild(codigoAtendimento);
    List<FichaAtendimentoDomiciliarChildTransport> listAtendimentosDomiciliaresChild = new ArrayList<>();
    while (rs.next()) {
      FichaAtendimentoDomiciliarChildTransport fichaAtendimentoDomiciliarChildTransport = new FichaAtendimentoDomiciliarChildTransport();

      String cns = rs.getString("cns");
      Long sexo = getCodigoSexo(rs.getString("sexo"));

      if (isBlank(cns)) {
        fichaAtendimentoDomiciliarChildTransport.setCpfCidadao(rs.getString("cpf"));
      } else {
        fichaAtendimentoDomiciliarChildTransport.setCnsCidadao(rs.getString("cns"));
      }

      fichaAtendimentoDomiciliarChildTransport.setSexo(sexo);
      fichaAtendimentoDomiciliarChildTransport.setLocalAtendimento(rs.getLong("local_atendimento"));
      fichaAtendimentoDomiciliarChildTransport.setAtencaoDomiciliarModalidade(rs.getLong("atencao_domiciliar_modalidade"));
      fichaAtendimentoDomiciliarChildTransport.setTipoAtendimento(rs.getLong("tipo_atendimento"));
      fichaAtendimentoDomiciliarChildTransport.setCid(rs.getString("cid"));
      fichaAtendimentoDomiciliarChildTransport.setCiap(rs.getString("ciap"));
      fichaAtendimentoDomiciliarChildTransport.setCondutaDesfecho(rs.getLong("conduta_desfecho"));
      fichaAtendimentoDomiciliarChildTransport.setDataNascimento(dateToEpoch(rs.getDate("data_nascimento")));
      fichaAtendimentoDomiciliarChildTransport.setTurno(rs.getLong("turno"));

      resolveCondicoesAvaliadas(fichaAtendimentoDomiciliarChildTransport, rs.getLong("codigo_atendimento"));
      resolveProcedimentos(fichaAtendimentoDomiciliarChildTransport, rs.getLong("codigo_atendimento"));

      listAtendimentosDomiciliaresChild.add(fichaAtendimentoDomiciliarChildTransport);
    }
    rs.close();
    fichaTransport.setAtendimentosDomiciliares(listAtendimentosDomiciliaresChild);
  }

  private Long getCodigoSexo(String sexo) {
    Long COD_SEXO_MASCULINO = 0L;
    Long COD_SEXO_FEMININO = 1L;
    Long COD_SEXO_IGNORADO = 4L;

    if("M".equalsIgnoreCase(sexo)){
      return COD_SEXO_MASCULINO;
    }

    if("F".equalsIgnoreCase(sexo)){
      return COD_SEXO_FEMININO;
    }

    return COD_SEXO_IGNORADO;
  }

  private void resolveCondicoesAvaliadas(FichaAtendimentoDomiciliarChildTransport fichaTransport, Long atendimentoCodigo) throws SQLException {
    ResultSet rs = bancoFichaAtendimentoDomiciliar.getCondicoesAvaliadas(atendimentoCodigo);
    List<Long> listCondicoes = new ArrayList<>();
    while (rs.next()) {
      listCondicoes.add(rs.getLong("condicao"));
    }
    rs.close();
    fichaTransport.setCondicoesAvaliadas(listCondicoes);
  }

  private void resolveProcedimentos(FichaAtendimentoDomiciliarChildTransport fichaTransport, Long atendimentoCodigo) throws SQLException {
    ResultSet rs = bancoFichaAtendimentoDomiciliar.getProcedimentos(atendimentoCodigo);
    List<String> listProcedimentos = new ArrayList<>();
    while (rs.next()) {
      listProcedimentos.add(rs.getString("procedimento"));
    }
    rs.close();
    fichaTransport.setProcedimentos(listProcedimentos);
  }
}
