class Contabilidade::LoteBancario < ApplicationRecord
	has_paper_trail
	include TradutorConcern

	belongs_to :banco, class_name: "Base::Banco", required: false
	belongs_to :agencia, class_name: 'Base::Agencia', required: false
	belongs_to :conta_bancaria, class_name: "Base::ContaBancaria", required: true

	has_many :pagamentos_do_lote_bancario, class_name: "Contabilidade::PagamentoDoLoteBancario", dependent: :destroy
	accepts_nested_attributes_for :pagamentos_do_lote_bancario, reject_if: :all_blank, allow_destroy: true

	attr_default :status, :gerado

	validates_presence_of :envio_ao_banco, :data_do_lote, :tipo
	validate :valida_quantidade_de_itens

	before_create :ler_dados_da_conta_bancaria
	after_create :gerar_lista_de_pagamentos, unless: proc { self.transferencia? }
	after_create :gerar_lista_de_retencoes, unless: proc { self.transferencia? }
	after_create :gerar_lista_de_transferencias, unless: proc { self.pagamento? }
	after_create :gerar_lista_de_despesas_extra, unless: proc { self.transferencia? }
	before_save :cancelar_itens, if: proc { self.status_changed?(from: "gerado", to: "cancelado") || self.status_changed?(from: "finalizado", to: "cancelado") }

	scope :ativos, -> { where("status in (1,2)") }

	enum envio_ao_banco: {
		relatorio: 1,
		arquivo: 2
	}

	enum status: {
		gerado: 1,
		finalizado: 2,
		cancelado: 3
	}

	enum tipo: {
		pagamento: 1,
		transferencia: 2,
		despesa_extra: 3
	}

	def pode_imprimir_arquivo?
		self.arquivo? && self.finalizado? && self.conta_bancaria.convenio_bancario.present?
	end

	def numero
		self.id.present? ? self.id.to_s.rjust(5, "0") : ""
	end

	def codigo_re
    "RE#{self.id.to_s.rjust(9, '0')}"
  end

	def ler_dados_da_conta_bancaria
		if conta_bancaria.present?
			agencia = conta_bancaria.agencia
			banco = conta_bancaria.try(:agencia).try(:banco)
		end
	end

	def total
		total_pagamentos = self.pagamentos_do_lote_bancario.where("conta_bancaria_por_pagamento_id > 0").inject(0) { |total, pagamento_do_lote_bancario|
			total + pagamento_do_lote_bancario.conta_bancaria_por_pagamento.valor_pago.to_d
		}
		total_retencoes = self.pagamentos_do_lote_bancario.where("pagamento_da_retencao_id > 0").inject(0) { |total, pagamento_do_lote_bancario|
			total + pagamento_do_lote_bancario.try(:pagamento_da_retencao).try(:retencao).try(:valor_calculado).to_d
		}
		total_transferencias = self.pagamentos_do_lote_bancario.where("transferencia_financeira_id > 0").inject(0) { |total, pagamento_do_lote_bancario|
			total + pagamento_do_lote_bancario.transferencia_financeira.valor
		}
		total_despesa_extra = self.pagamentos_do_lote_bancario.where("despesa_extra_orcamentaria_id > 0").inject(0) { |total, pagamento_do_lote_bancario| 
			total + pagamento_do_lote_bancario.try(:despesa_extra_orcamentaria).try(:valor_da_despesa).to_d
		}

		total_pagamentos + total_retencoes + total_transferencias + total_despesa_extra
	end

	def sugestao_numero_do_lote
		numeros_utilizados = Contabilidade::LoteBancario.all.pluck(:numero).map{ |numero| numero.to_i }
		return '00001' if numeros_utilizados.empty?

		numeros_utilizados = numeros_utilizados.to_a.sort
		numeros_disponiveis = (1..numeros_utilizados.last + 1).to_a - numeros_utilizados
		numeros_disponiveis.first.digitos(5)
	end

	def texto_para_arquivo
		texto = "00000000000000000000000000000000000#{self.data_do_lote.strftime("%d%m%Y")}#{self.data_do_lote.strftime("%H%M")}#{self.numero}10B001#{conta_bancaria.convenio_bancario.codigo.to_s[0..8].rjust(9, '0')}                                                                                                                                                                                                                                                                                    0000001\r\n"
		i = 1
		total = 1
		self.pagamentos_do_lote_bancario.each do |pagamento_do_lote_bancario|
			i += 1
			total += i
			pagamento_do_lote_bancario.ordem = i
			texto += pagamento_do_lote_bancario.linha_ob_600.gsub("#######", i.to_s.rjust(7, "0"))
		end
		valor_total = "%.2f" % self.total.to_f.round(2)
		texto += "99999999999999999999999999999999999                                                                                                                                                                                                                                                                                             #{valor_total.gsub(".", "").rjust(17, '0')}#{(total.to_i).to_s.rjust(13, '0')}\r\n"
	end

	def pagamento_principal
		return "" if self.pagamentos_do_lote_bancario.empty?

		if self.pagamentos_do_lote_bancario.size.to_i == 1
			self.pagamentos_do_lote_bancario.first.conta_bancaria_por_pagamento.pagamento.numero
		else
			"Qtd: #{self.pagamentos_do_lote_bancario.size.to_i}"
		end
	end

	def valida_quantidade_de_itens
		errors.add(:conta_bancaria_id, "deve conter itens") if self.pagamentos_do_lote_bancario.reject(&:marked_for_destruction?).empty?
	end

	def gerar_lista_de_pagamentos
		condicoes = []
		condicoes << "contabilidade_pagamentos.data >= '#{periodo_inicial.to_date.strftime('%F')}'" if self.periodo_inicial.present?
		condicoes << "contabilidade_pagamentos.data <= '#{periodo_final.to_date.strftime('%F')}'" if self.periodo_final.present?
		pagamentos_pendentes = Base::ContaBancariaPorPagamento.joins(:pagamento).where("conta_bancaria_id = ? and contabilidade_pagamentos.estornado is not true and contabilidade_pagamentos.status = 3 and contabilidade_pagamentos.orcamento_id = ?", self.conta_bancaria_id, contexto_atual.id)
		pagamentos_pendentes = pagamentos_pendentes.where(condicoes.join(" and ").to_s) if condicoes.size.positive?

		pagamentos_pendentes = pagamentos_pendentes.order("data ASC").all.map { |p| p unless p.esta_em_um_lote? }.compact

		pagamentos_pendentes.each do |pagamento_pendente|
			self.pagamentos_do_lote_bancario.build(conta_bancaria_por_pagamento: pagamento_pendente)
		end
	end

	def gerar_lista_de_retencoes
		condicoes = []
		condicoes << "contabilidade_pagamentos.data >= '#{periodo_inicial.to_date.strftime('%F')}'" if self.periodo_inicial.present?
		condicoes << "contabilidade_pagamentos.data <= '#{periodo_final.to_date.strftime('%F')}'" if self.periodo_final.present?

		retencoes_pentendes = Contabilidade::PagamentoDaRetencao.joins(retencao: :pagamento).where("contabilidade_pagamentos.estornado is not true and contabilidade_pagamentos.orcamento_id = ?", contexto_atual.id).where(conta_origem_id: self.conta_bancaria_id)
		retencoes_pentendes = retencoes_pentendes.where(condicoes.join(" and ").to_s) if condicoes.size.positive?
		retencoes_pentendes = retencoes_pentendes.order("contabilidade_pagamentos.data ASC").all.map { |p| p unless p.esta_em_um_lote? }.compact

		retencoes_pentendes.each do |retencao_pendente|
			self.pagamentos_do_lote_bancario.build(pagamento_da_retencao: retencao_pendente)
		end
	end

	def gerar_lista_de_transferencias
		condicoes = []

		condicoes << "data >= '#{periodo_inicial.to_time.beginning_of_day.strftime('%F %T')}'" if self.periodo_inicial.present?
		condicoes << "data <= '#{periodo_final.to_time.end_of_day.strftime('%F %T')}'" if self.periodo_final.present?

		transferencias_pendentes = Contabilidade::TransferenciaFinanceira.where(status: :confirmado, orcamento: contexto_atual).where("conta_bancaria_origem_id in (?)", self.conta_bancaria.unidades_do_orcamento(contexto_atual).pluck(:id))
		transferencias_pendentes = transferencias_pendentes.where(condicoes.join(" and ").to_s) if condicoes.size.positive?
		transferencias_pendentes = transferencias_pendentes.order("data ASC").all.map { |p| p unless p.esta_em_um_lote? }.compact

		transferencias_pendentes.each do |transferencia_financeira|
			self.pagamentos_do_lote_bancario.build(transferencia_financeira: transferencia_financeira)
		end
	end

	def gerar_lista_de_despesas_extra
		condicoes = []

		condicoes << "data_de_emissao >= '#{periodo_inicial.to_time.beginning_of_day.strftime('%F %T')}'" if self.periodo_inicial.present?
		condicoes << "data_de_emissao <= '#{periodo_final.to_time.end_of_day.strftime('%F %T')}'" if self.periodo_final.present?

		despesas_extra_pendentes = Contabilidade::DespesaExtraOrcamentaria.where("contabilidade_despesas_extra_orcamentarias.estornada is false and contabilidade_despesas_extra_orcamentarias.orcamento_id = ?", contexto_atual.id)
		despesas_extra_pendentes = despesas_extra_pendentes.where(condicoes.join(" and ").to_s) if condicoes.size.positive?
		despesas_extra_pendentes = despesas_extra_pendentes.order("data_de_emissao ASC").all.map { |p| p unless p.esta_em_um_lote? }.compact

		despesas_extra_pendentes.each do |despesa_extra_pendente|
			self.pagamentos_do_lote_bancario.build(despesa_extra_orcamentaria: despesa_extra_pendente)
		end
	end

	def cancelar_itens
		self.pagamentos_do_lote_bancario.where("conta_bancaria_por_pagamento_id > 0").each do |pagamento_do_lote_bancario|
			pagamento_do_lote_bancario.conta_bancaria_por_pagamento.pagamento.update_column(:status, :aguardando_lote)
		end
	end

end
