class Contabilidade::PagamentoDoLoteBancario < ApplicationRecord
  has_paper_trail

  attr_accessor :ordem

  belongs_to :lote_bancario, class_name: "Contabilidade::LoteBancario"
  belongs_to :conta_bancaria_por_pagamento, class_name: "Base::ContaBancariaPorPagamento"
  belongs_to :pagamento_da_retencao, class_name: "Contabilidade::PagamentoDaRetencao"
  belongs_to :transferencia_financeira, class_name: "Contabilidade::TransferenciaFinanceira"
  belongs_to :despesa_extra_orcamentaria, class_name: "Contabilidade::DespesaExtraOrcamentaria"

  before_create :gerar_numero
  after_create :atualizar_pagamento_para_lote_gerado
  after_destroy :atualizar_pagamento_para_aguardando_lote

  validate :valida_existe_em_outro_lote_ativo
  validate :valida_conta_destino
  validate :valida_pagamento_completo, if: proc { Configuracao.last.gerar_lote_somente_com_pagamento_completo? }

  scope :com_transferencia_financeira_presente, -> {where("transferencia_financeira_id IS NOT null")}

  def pagamento
    if self.conta_bancaria_por_pagamento.present?
      self.conta_bancaria_por_pagamento.pagamento
    elsif self.pagamento_da_retencao.present?
      self.pagamento_da_retencao.pagamento
    end
  end

  def gerar_numero
    if self.numero.to_i == 0
      prefixo = self.created_at.to_date.year.to_s[2..3]
      minimo = (prefixo + '0000000').to_i
      maximo = minimo + 9999999
      ultimo_numero = Contabilidade::PagamentoDoLoteBancario.where("numero between ? and ?", minimo, maximo).select(:numero).order("numero desc").first.numero rescue (prefixo + '0000000').to_i
      
      self.numero = ultimo_numero + 1
    end
  end

  def valida_existe_em_outro_lote_ativo
    if self.conta_bancaria_por_pagamento.present?
      errors.add(:id, "já está em outro lote") if Contabilidade::PagamentoDoLoteBancario.joins(:lote_bancario).where(contabilidade_lotes_bancarios: { status: [1, 2]}).where(conta_bancaria_por_pagamento_id: self.conta_bancaria_por_pagamento_id).size > 0
    elsif self.pagamento_da_retencao.present?
      errors.add(:id, "já está em outro lote") if Contabilidade::PagamentoDoLoteBancario.joins(:lote_bancario).where(contabilidade_lotes_bancarios: { status: [1, 2]}).where(pagamento_da_retencao_id: self.pagamento_da_retencao_id).size > 0
    elsif self.transferencia_financeira.present?
      errors.add(:id, "já está em outro lote") if Contabilidade::PagamentoDoLoteBancario.joins(:lote_bancario).where(contabilidade_lotes_bancarios: { status: [1, 2]}).where(transferencia_financeira_id: self.transferencia_financeira_id).size > 0
    elsif self.despesa_extra_orcamentaria.present?
      errors.add(:id, "já está em outro lote") if Contabilidade::PagamentoDoLoteBancario.joins(:lote_bancario).where(contabilidade_lotes_bancarios: { status: [1, 2]}).where(despesa_extra_orcamentaria_id: self.despesa_extra_orcamentaria_id).size > 0
    end
  end

  def valida_pagamento_completo
    if self.conta_bancaria_por_pagamento.present?
      errors.add(:id, "possui retenções pendentes de geração de pagamento") if self.conta_bancaria_por_pagamento.pagamento.possui_retencoes_pendentes_de_pagamento?
    end
  end

  def valida_conta_destino
    if self.conta_bancaria_por_pagamento.present?
      errors.add(:id, "pagamento não tem conta destino informada.") if self.try(:conta_bancaria_por_pagamento).try(:pagamento).try(:pessoa_conta_bancaria).try(:nil?)
    elsif self.pagamento_da_retencao.present?
      errors.add(:id, "retenção não tem conta destino informada.") if self.try(:pagamento_da_retencao).try(:conta_destino).try(:nil?)
    end
  end

  def atualizar_pagamento_para_lote_gerado
    if self.conta_bancaria_por_pagamento.present?
      self.conta_bancaria_por_pagamento.pagamento.update_attribute(:status, :lote_gerado)
    end
  end

  def atualizar_pagamento_para_aguardando_lote
    if self.conta_bancaria_por_pagamento.present?
      qtd_de_pagamentos_em_lote = self.conta_bancaria_por_pagamento&.pagamento&.numeros_dos_lotes&.size.to_i + self.conta_bancaria_por_pagamento&.pagamento&.numeros_dos_lotes_das_retencoes&.size.to_i
      self.conta_bancaria_por_pagamento.pagamento.update_attribute(:status, :aguardando_lote) unless qtd_de_pagamentos_em_lote.positive?
    elsif self.pagamento_da_retencao
      qtd_de_pagamentos_em_lote = self.pagamento_da_retencao&.pagamento&.numeros_dos_lotes&.size.to_i + self.pagamento_da_retencao&.pagamento&.numeros_dos_lotes_das_retencoes&.size.to_i
      self.pagamento_da_retencao.pagamento.update_attribute(:status, :aguardando_lote) unless qtd_de_pagamentos_em_lote.positive?
    end
  end

  def codigo_ob
    "OB#{self.numero.to_s.rjust(9, '0')}"
  end

  def codigo_re
    self.lote_bancario.codigo_re
  end

  def tipo_de_ob
    if self.conta_bancaria_por_pagamento.present?
      self.conta_bancaria_por_pagamento.pagamento.try(:pessoa_conta_bancaria).try(:banco).try(:numero_do_banco).to_i == 1 ? "32" : "31"
    elsif self.pagamento_da_retencao.present?
      self.pagamento_da_retencao.try(:conta_destino).try(:agencia).try(:banco).try(:numero_do_banco).to_i == 1 ? "32" : "31"
    end
  end

  def tipo
    if self.conta_bancaria_por_pagamento.present?
      "PAGAMENTO"
    elsif self.pagamento_da_retencao.present?
      "RETENÇÃO"
    elsif self.transferencia_financeira.present?
      "TRANSFERÊNCIA"
    elsif self.despesa_extra_orcamentaria.present?
      "DESPESA EXTRA"
    end
  end

  def linha_ob_600
    if self.conta_bancaria_por_pagamento.present?
      self.linha_ob_600_pagamento
    elsif self.pagamento_da_retencao.present?
      self.linha_ob_600_retencao
    end
  end

  def linha_ob_600_pagamento
    begin
      linha = "2"
      linha = linha + "#{self.conta_bancaria_por_pagamento.conta_bancaria.agencia.numero_da_agencia.to_s.strip.gsub("-", "").gsub(".", "").rjust(5, '0')}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.conta_bancaria.try(:codigo_ug).to_s.rjust(6, '0')}" # => codigo da UG
      linha = linha + "#{self.conta_bancaria_por_pagamento.conta_bancaria.try(:codigo_gestao).to_s.rjust(5, '0')}" # => codigo da Unidade Orgão
      linha = linha + self.codigo_re # => RE
      linha = linha + self.codigo_ob
      linha = linha + "#{self.created_at.strftime("%d%m%Y")}"
      linha = linha + "    "
      linha = linha + self.tipo_de_ob
      linha = linha + "0" # => 0 pagamento normal - 1 pagamento de salário
      linha = linha + "000000000"
      valor = "%.2f" % self.conta_bancaria_por_pagamento.valor_pago.to_f.round(2)
      linha = linha + "#{valor.gsub(".", "").rjust(17, '0')}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:pessoa_conta_bancaria).try(:banco).try(:numero_do_banco).to_s.strip.rjust(3, '0')}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:pessoa_conta_bancaria).try(:agencia_com_digito).to_s.strip.gsub(".", "").gsub("-", "").rjust(5, '0')}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:pessoa_conta_bancaria).try(:numero_da_conta).to_s.strip.gsub(".", "").gsub("-", "").rjust(10, '0').try(:upcase)}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:nome).to_s.strip[0..44].ljust(45, " ")}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:endereco_com_bairro).to_s.strip[0..56].ljust(57, " ")}"
      linha = linha + "00000000" # ISPB do favorecido
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:cidade).try(:nome).strip[0..27].ljust(28, ' ')}"
      linha = linha + "                 " # => código gru
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:cep).to_s.gsub("-", "").strip[0..7].ljust(8, ' ')}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:uf_endereco).to_s.strip[0..1].ljust(2, ' ')}"
      linha = linha + "                                        " # => observação
      linha = linha + "0" # => 0 não prioritário 1 - prioritário
      if self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:pessoa_fisica?)
        linha = linha + "2"
      elsif self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:pessoa_juridica?)
        linha = linha + "1"
      else
        linha = linha + "5" # => GRU
      end
      linha = linha + "#{self.conta_bancaria_por_pagamento.pagamento.try(:credor).try(:cpf_ou_cnpj_sem_pontos).to_s.strip[0..13].ljust(14, ' ')}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.conta_bancaria.agencia.numero_da_agencia.to_s.strip.gsub("-", "").gsub(".", "").rjust(5, '0')[0..4]}"
      linha = linha + "#{self.conta_bancaria_por_pagamento.conta_bancaria.numero_da_conta.to_s.strip.gsub("-", "").gsub(".", "").rjust(10, '0')[0..9].try(:upcase)}"
      linha = linha + "000" # => fundeb
      linha = linha + "    "
      linha = linha + "00" # => código de retorno
      linha = linha + "#{self.ordem.to_s.rjust(7, '0')}\r\n"
    rescue
      linha = "99 ERRO AO GERAR DADOS"
    end
  end

  def linha_ob_600_retencao
    begin
      linha = "2"
      linha = linha + "#{self.pagamento_da_retencao.conta_origem.agencia.numero_da_agencia.to_s.strip.gsub("-", "").gsub(".", "").rjust(5, '0')}"
      linha = linha + "#{self.pagamento_da_retencao.conta_origem.try(:codigo_ug).to_s.rjust(6, '0')}" # => codigo da UG
      linha = linha + "#{self.pagamento_da_retencao.conta_origem.try(:codigo_gestao).to_s.rjust(5, '0')}" # => codigo da Unidade Orgão
      linha = linha + self.codigo_re # => RE
      linha = linha + self.codigo_ob
      linha = linha + "#{self.created_at.strftime("%d%m%Y")}"
      linha = linha + "    "
      linha = linha + self.tipo_de_ob
      linha = linha + "0" # => 0 pagamento normal - 1 pagamento de salário
      linha = linha + "000000000"
      valor = "%.2f" % self.pagamento_da_retencao.retencao.valor_calculado.to_f.round(2)
      linha = linha + "#{valor.gsub(".", "").rjust(17, '0')}"
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:agencia).try(:banco).try(:numero_do_banco).to_s.strip.rjust(3, '0')}"
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:agencia).try(:numero_da_agencia).to_s.strip.gsub(".", "").gsub("-", "").rjust(5, '0')}"
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:numero_da_conta).to_s.strip.gsub(".", "").gsub("-", "").rjust(10, '0').try(:upcase)}"
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:unidade_orcamentaria_principal).try(:nome).to_s.strip[0..44].ljust(45, " ")}"
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:unidade_orcamentaria_principal).try(:orgao).try(:endereco).to_s.strip[0..56].ljust(57, " ")}"
      linha = linha + "00000000" # ISPB do favorecido
      linha = linha + "#{Configuracao.last.cidade.nome.strip[0..27].ljust(28, ' ')}"
      linha = linha + "                 " # => código gru
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:unidade_orcamentaria_principal).try(:orgao).try(:cep).to_s.gsub("-", "").strip[0..7].ljust(8, ' ')}"
      linha = linha + "#{Configuracao.last.estado.uf.to_s.strip[0..1].ljust(2, ' ')}"
      linha = linha + "                                        " # => observação
      linha = linha + "0" # => 0 não prioritário 1 - prioritário
      linha = linha + "1"
      linha = linha + "#{self.pagamento_da_retencao.try(:conta_destino).try(:unidade_orcamentaria_principal).try(:orgao).try(:cnpj).to_s.strip[0..13].ljust(14, ' ')}"
      linha = linha + "#{self.pagamento_da_retencao.conta_origem.agencia.numero_da_agencia.to_s.strip.gsub("-", "").gsub(".", "").rjust(5, '0')[0..4]}"
      linha = linha + "#{self.pagamento_da_retencao.conta_origem.numero_da_conta.to_s.strip.gsub("-", "").gsub(".", "").rjust(10, '0')[0..9].try(:upcase)}"
      linha = linha + "000" # => fundeb
      linha = linha + "    "
      linha = linha + "00" # => código de retorno
      linha = linha + "#{self.ordem.to_s.rjust(7, '0')}\r\n"
    rescue
      linha = "99 ERRO AO GERAR DADOS"
    end
  end
end
