require 'active_support/concern'

module Tcm::ValidarArquivoConcern extend ActiveSupport::Concern

  def validar
    self.erros_do_arquivo.delete_all
    if self.contabilidade?
      valida_balancetes_pcasp
      valida_balancetes_orcamentarios
      valida_balancetes_extra_orcamentarios
      valida_folhas_de_pagamento
      valida_outros_arquivos
    end
    if self.orcamento?
      valida_orcamento_da_receita
    end
  end

  def carregar_dados_do_arquivo(sigla_arquivo)
    arquivo = arquivos.where("nome ilike '#{sigla_arquivo}%'").first
    dados = CSV.parse(arquivo.conteudo, quote_char: '"', force_quotes: true).map { |linha| linha.map(&:strip) } rescue []

    return dados
  end

  def valida_balancetes_pcasp
    bb = carregar_dados_do_arquivo("BB")
    bc = carregar_dados_do_arquivo("BC")
    ba = carregar_dados_do_arquivo("BA")
    be = carregar_dados_do_arquivo("BE")
    
    if bb.size == 0 || bc.size == 0 || ba.size == 0 || be.size == 0
      return
    end

    bb_debitos = bb.inject(0) { |t, i| t + i[14].to_d }
    bb_creditos = bb.inject(0) { |t, i| t + i[15].to_d }

    bc_debitos = bc.inject(0) { |t, i| t + i[14].to_d }
    bc_creditos = bc.inject(0) { |t, i| t + i[15].to_d }

    be_debitos = be.inject(0) { |t, i| t + i[12].to_d }
    be_creditos = be.inject(0) { |t, i| t + i[13].to_d }

    ba_debitos = ba.inject(0) { |t, i| t + i[20].to_d }
    ba_creditos = ba.inject(0) { |t, i| t + i[21].to_d }
    
    total_debito = bb_debitos + bc_debitos + be_debitos + ba_debitos
    total_credito = bb_creditos + bc_creditos + be_creditos + ba_creditos

    if total_debito != total_credito
      self.erros_do_arquivo.create(descricao: "Total de débitos e creditos dos arquivos BB, BC, BE e BA são diferentes. Debitos: #{total_debito.to_f.contabil} Creditos: #{total_credito.to_f.contabil}")
    end

    if be_debitos != be_creditos
      self.erros_do_arquivo.create(descricao: "Total de debito e creditos dos arquivos BE são diferentes. Debitos: #{be_debitos.to_f.contabil} Creditos: #{be_creditos.to_f.contabil}")
    end

    if ba_debitos != ba_creditos
      self.erros_do_arquivo.create(descricao: "Total de debito e creditos dos arquivos BA são diferentes. Debitos: #{ba_debitos.to_f.contabil} Creditos: #{ba_creditos.to_f.contabil}")
    end

    if ba_creditos.zero?
      self.erros_do_arquivo.create(descricao: "Total de credito dos arquivos BA não pode ser zero.")
    end

    if be_creditos.zero?
      self.erros_do_arquivo.create(descricao: "Total de credito dos arquivos BE não pode ser zero.")
    end

    if bb_creditos.zero?
      self.erros_do_arquivo.create(descricao: "Total de credito dos arquivos BB não pode ser zero.")
    end

    if bc_creditos.zero?
      self.erros_do_arquivo.create(descricao: "Total de credito dos arquivos BC não pode ser zero.")
    end

    if ba_debitos.zero?
      self.erros_do_arquivo.create(descricao: "Total de debito dos arquivos BA não pode ser zero.")
    end

    if be_debitos.zero?
      self.erros_do_arquivo.create(descricao: "Total de debito dos arquivos BE não pode ser zero.")
    end

    if bb_debitos.zero?
      self.erros_do_arquivo.create(descricao: "Total de debito dos arquivos BB não pode ser zero.")
    end

    if bc_debitos.zero?
      self.erros_do_arquivo.create(descricao: "Total de debito dos arquivos BC não pode ser zero.")
    end
  end

  def valida_balancetes_orcamentarios
    br = carregar_dados_do_arquivo("BR")
    bd = carregar_dados_do_arquivo("BD")
    tr = carregar_dados_do_arquivo("TR")
    ne = carregar_dados_do_arquivo("NE")
    lq = carregar_dados_do_arquivo("LQ")
    np = carregar_dados_do_arquivo("NP")
    at = carregar_dados_do_arquivo("AT")

    exercicio_sim = "#{self.orcamento.exercicio}00"

    br_total = br.inject(0) { |t, i| t + i[13].to_d }
    tr_total = tr.inject(0) { |t, i| t + i[11].to_d }
    br_total_anulado = br.inject(0) { |t, i| t + i[11].to_d }
    at_total = at.inject(0) { |t, i| t + i[13].to_d }

    bd_empenhos_total = bd.inject(0) { |t, i| t + i[26].to_d }
    bd_liquidacoes_total = bd.inject(0) { |t, i| t + i[31].to_d }
    bd_pagamentos_total = bd.inject(0) { |t, i| t + i[35].to_d }

    ne_total = ne.select{ |i| i[2] == exercicio_sim }.inject(0) { |t, i| t + i[21].to_d }
    lq_total = lq.select{ |i| i[2] == exercicio_sim }.inject(0) { |t, i| t + i[12].to_d }
    np_total = np.select{ |i| i[2] == exercicio_sim }.inject(0) { |t, i| t + i[12].to_d }

    if br_total != tr_total
      self.erros_do_arquivo.create(descricao: "Total de receitas dos arquivos BR e TR não são iguais. BR: #{br_total.to_f.contabil} TR: #{tr_total.to_f.contabil}")
    end

    if br_total_anulado != at_total
      self.erros_do_arquivo.create(descricao: "Total de anulaçoes receitas dos arquivos BR e AT não são iguais. BR: #{br_total_anulado.to_f.contabil} AT: #{at_total.to_f.contabil}")
    end

    if bd_empenhos_total != ne_total
      self.erros_do_arquivo.create(descricao: "Total de empenhos dos arquivos BD e NE não são iguais. BD: #{bd_empenhos_total.to_f.contabil} NE: #{ne_total.to_f.contabil}")
    end

    if bd_liquidacoes_total != lq_total
      self.erros_do_arquivo.create(descricao: "Total de liquidações dos arquivos BD e LQ não são iguais. BD: #{bd_liquidacoes_total.to_f.contabil} LQ: #{lq_total.to_f.contabil}")
    end

    if bd_pagamentos_total != np_total
      self.erros_do_arquivo.create(descricao: "Total de pagamentos dos arquivos BD e NP não são iguais. BD: #{bd_pagamentos_total.to_f.contabil} NP: #{np_total.to_f.contabil}")
    end

  end

  def valida_balancetes_extra_orcamentarios
    rx = carregar_dados_do_arquivo("RX")
    dx = carregar_dados_do_arquivo("DX")
    tx = carregar_dados_do_arquivo("TX")
    xd = carregar_dados_do_arquivo("XD")

    rx_total = rx.inject(0) { |t, i| t + i[10].to_d }
    dx_total = dx.inject(0) { |t, i| t + i[10].to_d }
    tx_total = tx.inject(0) { |t, i| t + i[9].to_d }
    xd_total = xd.inject(0) { |t, i| t + i[13].to_d } + xd.inject(0) { |t, i| t + i[14].to_d }

    if rx_total != tx_total
      self.erros_do_arquivo.create(descricao: "Total de receitas dos arquivos RX e TX não são iguais. RX: #{rx_total.to_f.contabil} TX: #{tx_total.to_f.contabil}")
    end

    if dx_total != xd_total
      self.erros_do_arquivo.create(descricao: "Total de despesas dos arquivos DX e XD não são iguais. DX: #{dx_total.to_f.contabil} XD: #{xd_total.to_f.contabil}")
    end
  end

  def valida_orcamento_da_receita
    re = carregar_dados_do_arquivo("RE")
    de = carregar_dados_do_arquivo("DE")
    pa = carregar_dados_do_arquivo("PA")
    ep = carregar_dados_do_arquivo("EP")

    if re.size == 0
      return
    end

    re_total = re.inject(0) { |t, i| t + i[9].to_d }
    de_total = de.inject(0) { |t, i| t + i[7].to_d }
    pa_total = pa.inject(0) { |t, i| t + i[14].to_d }
    ep_total = ep.inject(0) { |t, i| t + i[14].to_d }

    if re_total != de_total
      self.erros_do_arquivo.create(descricao: "Total de receitas RE é diferente do total de despesas DE. Receitas: #{re_total.to_f.contabil} Despesas: #{de_total.to_f.contabil}")
    end

    if re_total != pa_total
      self.erros_do_arquivo.create(descricao: "Total de receitas RE é diferente do total de despesas PA. Receitas: #{re_total.to_f.contabil} Parcelas: #{pa_total.to_f.contabil}")
    end

    if re_total != ep_total
      self.erros_do_arquivo.create(descricao: "Total de receitas RE é diferente do total de despesas EP. Receitas: #{re_total.to_f.contabil} Parcelas: #{ep_total.to_f.contabil}")
    end

  end

  def valida_outros_arquivos
    nf = carregar_dados_do_arquivo("NF")
    iff = carregar_dados_do_arquivo("IF")

    nf_total = nf.inject(0) { |t, i| t + i[21].to_d }
    iff_total = iff.inject(0) { |t, i| t + i[15].to_d }

    if nf_total != iff_total && iff_total != 0 && nf_total != 0
      self.erros_do_arquivo.create(descricao: "Total de notas fiscais e itens das notas fiscais não são iguais. NF: #{nf_total.to_f.contabil} IF: #{iff_total.to_f.contabil}")
    end

    notas_ = nf.map { |i| [ i[2], i[3], i[4], i[5], i[6], i[7], i[8], i[9] ] }
    itens_ = iff.map { |i| [ i[2], i[3], i[4], i[5], i[6], i[7], i[8], i[9] ] }.uniq
    if (notas_ - itens_) != []
      lista = notas_ - itens_
      lista.each do |item|
        self.erros_do_arquivo.create(descricao: "ITEM/NOTA FISCAL NÃO ENCONTRADO(A) NOS ARQUIVOS #{item.join(",")}")
      end
    end

  end

  def valida_folhas_de_pagamento
    fp = carregar_dados_do_arquivo("FP")
    lq = carregar_dados_do_arquivo("LQ")
    af = carregar_dados_do_arquivo("AF")

    fp_total = fp.inject(0) { |t, i| t + i[9].to_d }
    lq_total = lq.inject(0) { |t, i| t + i[16].to_d }
    af_total = af.select{ |i| i[14] == "O"}.inject(0) { |t, i| t + i[13].to_d }

    if fp_total != lq_total
      self.erros_do_arquivo.create(descricao: "Total de folhas de pagamento FP e LQ não são iguais. FP: #{fp_total.to_f.contabil} LQ: #{lq_total.to_f.contabil}")
    end

    if fp_total != af_total
      self.erros_do_arquivo.create(descricao: "Total de folhas de pagamento FP e AF não são iguais. FP: #{fp_total.to_f.contabil} AF: #{af_total.to_f.contabil}")
    end

    fp.group_by{ |i| [i[3], i[4]]  }.each do |unidade, dados|
      fp_da_unidade = fp.select{ |i| i[3] == unidade[0] && i[4] == unidade[1] }.inject(0) { |t, i| t + i[9].to_d }
      lq_da_unidade = lq.select{ |i| i[3] == unidade[0] && i[4] == unidade[1] }.inject(0) { |t, i| t + i[16].to_d }
      
      if fp_da_unidade != lq_da_unidade
        self.erros_do_arquivo.create(descricao: "Total de folhas de pagamento da unidade #{unidade[0]}#{unidade[1]} FP e LQ não são iguais. FP: #{fp_da_unidade.to_f.contabil} LQ: #{lq_da_unidade.to_f.contabil}")
      end

      folhas_ = fp.select{ |i| i[3] == unidade[0] && i[4] == unidade[1] } .map { |i| [i[1], i[2], i[3], i[4], i[5], i[6], i[7], i[8], i[9].to_d] }
      liquidacoes_ = lq.select{ |i| i[3] == unidade[0] && i[4] == unidade[1] && i[16].to_d > 0 }.map { |i| [i[1], i[2], i[3], i[4], i[8], i[14], i[15], i[8], i[16]] }
        .group_by { |i| i[0..-2] }
        .map { |k, v| k + [v.map { |i| i[-1].to_d }.sum] }

      if (folhas_ - liquidacoes_) != []
        lista_folhas = folhas_ - liquidacoes_

        lista_folhas.each do |item|
          self.erros_do_arquivo.create(descricao: "FOLHA DE PAGAMENTO NÃO ENCONTRADO(A) NOS ARQUIVOS DE LIQUIDAÇÃO #{item.join(",")}")
        end

        lista_liquidacoes = liquidacoes_ - folhas_
        lista_liquidacoes.each do |item|
          self.erros_do_arquivo.create(descricao: "LIQUIDAÇÕES NÃO ENCONTRADO(A) NOS ARQUIVOS DE FOLHA #{item.join(",")}")
        end

      end
    end

  end
  
end