package br.com.elotech.controllers;

import br.com.elotech.commom.PROP_FILE;
import br.com.elotech.commom.Util;
import br.com.elotech.model.Dados;
import br.com.elotech.model.arquivo.Arquivo;
import br.com.elotech.model.arquivo.Reg00;
import br.com.elotech.model.arquivo.Reg98;
import br.com.elotech.model.arquivo.Reg99;
import br.com.elotech.model.familia.Familia;
import br.com.elotech.model.familia.membro.Membro;
import me.tongfei.progressbar.ProgressBar;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.text.ParseException;
import java.util.*;

/**
 * User: claiton.nazaret
 * Date: 20/02/2019
 * Time: 08:13
 */
public class MainController {

  private static final Logger logger = Logger.getLogger(MainController.class);

  private Properties prop;
  private Arquivo info = null;

  //posição do campo NUM-PROP_FILE-ARQUIVO
  private String NRA_POS="38";
  private String NRA_TAM="2";

  private int qtdFamilias = 0;
  private int qtdMembros = 0;

  public void executar(File file) throws Exception {
    try {
      Dados dados = new Dados();
      Familia familia = null;
      Membro membro = null;
      logger.info("Importacao dos dados iniciada");
      //Lê a quantidade de linhas do arquivo
      int numberLines = getTotalLinhas(file);
      Scanner s = new Scanner(new FileReader(file));
      try (ProgressBar pb = new ProgressBar("Carregando Dados...", numberLines)) {
        while (s.hasNextLine()){
          pb.step();
          String line = s.nextLine();
          String numreg = Util.getStringOfProp(line, NRA_POS, NRA_TAM);
          if(StringUtils.isNotBlank(numreg)){
            String REG = "REG".concat(numreg);
            PROP_FILE p = PROP_FILE.valueOf(REG);
            switch (p){
              case REG00:
              case REG98:{
                info = getInfo(info, line, p, file.getName());
                break;
              }
              case REG99:
                info = getInfo(info, line, p, file.getName());
                familia.getMembros().add(membro);
                dados.getFamilias().add(familia);
                break;
              // Familia
              case REG01:
                if(membro != null){
                  familia.getMembros().add(membro);
                  membro = null;
                }
              case REG02:
              case REG03:
              case REG09:
              case REG11:
              case REG13:
              case REG16:
              case REG17:
              case REG18:
                familia = (new FamiliaController(familia)).execute(dados, line, p);
                break;
              // Membro da familia
              case REG04:
              case REG05:
              case REG06:
              case REG07:
              case REG08:
              case REG12:
              case REG14:
              case REG15:
              case REG19:
                membro = (new MembroController(membro)).execute(familia, line, p);
                break;
            }
          }
        }
        dados.setArquivo(info);
      }
      s.close();

      logger.info("Importacao dos dados finalizado");

      //verifica se a quantidade de familias e membros foram corretamente importadas
      if(verificaFidelidadeDados(dados)){
        limpaFamiliasEMembrosExcluidos(dados);
        PersistenceController persist = new PersistenceController();
        if(persist.persisteDadosImportados(dados)){
          logger.info("Dados salvos com sucesso");
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      logger.error(e);
    }
    Util.excluiArquivo(file);
  }

  private int getTotalLinhas(File file) throws IOException {
    LineNumberReader lnr = new LineNumberReader(new FileReader(file));
    lnr.skip(file.length());
    return lnr.getLineNumber();
  }

  private boolean verificaFidelidadeDados(Dados dados) {
    qtdMembros = 0;
    for(Familia f : dados.getFamilias()){
        qtdMembros += f.getMembros().size();
    }

    int qtd_familia = Integer.parseInt(dados.getArquivo().getReg99().getQtdReg01Tlr());
    qtdFamilias = dados.getFamilias().size();
    if(qtdFamilias != qtd_familia){
      logger.error("Erro na importacao de familias:");
      logger.error("Esperado: " + qtd_familia + " ::: Importado: " + qtdFamilias + " familias");
      return false;
    }

    int qtd_membros = Integer.parseInt(dados.getArquivo().getReg99().getQtdReg04Tlr());
    if(qtdMembros != qtd_membros){
      logger.error("Erro na importacao de membros:");
      logger.error("Esperado: " + qtd_membros + " ::: Importado: " + qtdMembros + " membros");
      return false;
    }

    return true;
  }

  private void limpaFamiliasEMembrosExcluidos(Dados dados){
    int qtdFamiliasRemovidas = 0;
    int qtdMembrosRemovidos = 0;

    for(Iterator<Familia> f = dados.getFamilias().iterator(); f.hasNext();){
      Familia familia = f.next();
      if(Objects.nonNull(familia.getReg18()) || !familia.getReg16s().isEmpty()){
        qtdMembrosRemovidos += familia.getMembros().size();
        f.remove();
        qtdFamiliasRemovidas++;
      }else{
        for (Iterator<Membro> m = familia.getMembros().iterator(); m.hasNext();){
          Membro membro = m.next();
          if(Objects.nonNull(membro.getReg19())){
            m.remove();
            qtdMembrosRemovidos++;
          }
        }
        if(familia.getMembros().isEmpty()){
          qtdMembrosRemovidos += familia.getMembros().size();
          qtdFamiliasRemovidas++;
          f.remove();
        }
      }
    }

    if(qtdFamiliasRemovidas > 0){
      logger.warn(qtdFamiliasRemovidas + " / " + qtdFamilias + " familias removidas. ");
    }
    int sobrou = 0;
    if(qtdMembrosRemovidos > 0){
      for (Familia f : dados.getFamilias()){
        sobrou += f.getMembros().size();
      }
      logger.warn(qtdMembrosRemovidos + " / " + qtdMembros + " membros removidos.");
    }
    logger.info("Serao importadas " + dados.getFamilias().size() + " familias com " + sobrou + " membros");
  }

  private Arquivo getInfo(Arquivo arquivo, String line, PROP_FILE file, String nomeArquivo) throws ParseException {
    prop = Util.getProp(file);
    switch (file){
      case REG00:
        arquivo = new Arquivo();
        arquivo.setArquivo(nomeArquivo);
        arquivo.setDtImportacao(new Date());

        Reg00 reg00 = new Reg00();
        reg00.setNomArquivoHdr(Util.getStringOfProp(line, prop.getProperty("NOM_ARQUIVO_HDR.pos"), prop.getProperty("NOM_ARQUIVO_HDR.tam")));
        reg00.setCodVersaoLayoutHdr(Util.getStringOfProp(line, prop.getProperty("COD_VERSAO_LAYOUT_HDR.pos"), prop.getProperty("COD_VERSAO_LAYOUT_HDR.tam")));
        reg00.setDtaPosicaoCadastroHdr(Util.getDateOfProp(line, prop.getProperty("DTA_POSICAO_CADASTRO_HDR.pos"), prop.getProperty("DTA_POSICAO_CADASTRO_HDR.tam")));
        reg00.setDtaExtracaoDadosHdr(Util.getDateOfProp(line, prop.getProperty("DTA_EXTRACAO_DADOS_HDR.pos"), prop.getProperty("DTA_EXTRACAO_DADOS_HDR.tam")));
        arquivo.setReg00(reg00);
        break;
      case REG98:
        Reg98 reg98 = new Reg98();
        reg98.setChvNaturalPrefeitura(Util.getStringOfProp(line, prop.getProperty("CHV_NATURAL_PREFEITURA.pos"), prop.getProperty("CHV_NATURAL_PREFEITURA.tam")));
        reg98.setCodMunicIbge2Pre(Util.getStringOfProp(line, prop.getProperty("COD_MUNIC_IBGE_2_PRE.pos"), prop.getProperty("COD_MUNIC_IBGE_2_PRE.tam")));
        reg98.setCodMunicIbge5Pre(Util.getStringOfProp(line, prop.getProperty("COD_MUNIC_IBGE_5_PRE.pos"), prop.getProperty("COD_MUNIC_IBGE_5_PRE.tam")));
        reg98.setIndMigracaoPre(Util.getStringOfProp(line, prop.getProperty("IND_MIGRACAO_PRE.pos"), prop.getProperty("IND_MIGRACAO_PRE.tam")));
        reg98.setNomPrefeituraPre(Util.getStringOfProp(line, prop.getProperty("NOM_PREFEITURA_PRE.pos"), prop.getProperty("NOM_PREFEITURA_PRE.tam")));
        arquivo.setReg98(reg98);
        break;
      case REG99:
        Reg99 reg99 = new Reg99();
        reg99.setQtdReg00Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_00_TLR.pos"), prop.getProperty("QTD_REG_00_TLR.tam")));
        reg99.setQtdReg01Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_01_TLR.pos"), prop.getProperty("QTD_REG_01_TLR.tam")));
        reg99.setQtdReg02Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_02_TLR.pos"), prop.getProperty("QTD_REG_02_TLR.tam")));
        reg99.setQtdReg03Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_03_TLR.pos"), prop.getProperty("QTD_REG_03_TLR.tam")));
        reg99.setQtdReg04Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_04_TLR.pos"), prop.getProperty("QTD_REG_04_TLR.tam")));
        reg99.setQtdReg05Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_05_TLR.pos"), prop.getProperty("QTD_REG_05_TLR.tam")));
        reg99.setQtdReg06Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_06_TLR.pos"), prop.getProperty("QTD_REG_06_TLR.tam")));
        reg99.setQtdReg07Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_07_TLR.pos"), prop.getProperty("QTD_REG_07_TLR.tam")));
        reg99.setQtdReg08Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_08_TLR.pos"), prop.getProperty("QTD_REG_08_TLR.tam")));
        reg99.setQtdReg09Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_09_TLR.pos"), prop.getProperty("QTD_REG_09_TLR.tam")));
        reg99.setQtdReg10Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_10_TLR.pos"), prop.getProperty("QTD_REG_10_TLR.tam")));
        reg99.setQtdReg11Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_11_TLR.pos"), prop.getProperty("QTD_REG_11_TLR.tam")));
        reg99.setQtdReg12Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_12_TLR.pos"), prop.getProperty("QTD_REG_12_TLR.tam")));
        reg99.setQtdReg13Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_13_TLR.pos"), prop.getProperty("QTD_REG_13_TLR.tam")));
        reg99.setQtdReg14Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_14_TLR.pos"), prop.getProperty("QTD_REG_14_TLR.tam")));
        reg99.setQtdReg15Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_15_TLR.pos"), prop.getProperty("QTD_REG_15_TLR.tam")));
        reg99.setQtdReg16Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_16_TLR.pos"), prop.getProperty("QTD_REG_16_TLR.tam")));
        reg99.setQtdReg17Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_17_TLR.pos"), prop.getProperty("QTD_REG_17_TLR.tam")));
        reg99.setQtdReg18Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_18_TLR.pos"), prop.getProperty("QTD_REG_18_TLR.tam")));
        reg99.setQtdReg19Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_19_TLR.pos"), prop.getProperty("QTD_REG_19_TLR.tam")));
        reg99.setQtdReg98Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_98_TLR.pos"), prop.getProperty("QTD_REG_98_TLR.tam")));
        reg99.setQtdReg99Tlr(Util.getStringOfProp(line, prop.getProperty("QTD_REG_99_TLR.pos"), prop.getProperty("QTD_REG_99_TLR.tam")));
        arquivo.setReg99(reg99);
        break;
    }

    return arquivo;
  }

}
