class Contabilidade::EstornoDeDespesaExtraOrcamentaria < ApplicationRecord
	# include ReversorDeEventosContabeis
	# reversor_de_eventos_contabeis acao: 5, atributo_pai: 'despesa_extra_orcamentaria', atributo_data: 'data_do_estorno', atributo_codigo_movimentacao: 'numero_de_caixa'
	include GeradorDeEventosContabeis
	include IncrementadorDeCodigoConcern

	has_paper_trail

	belongs_to :despesa_extra_orcamentaria
	belongs_to :usuario, required: false
	belongs_to :orcamento
	belongs_to :arquivo, class_name: 'Tcm::Arquivo', required: false

	has_many :lancamentos_extraorcamentario_despesa, as: :modulo

	delegate :numero_de_caixa, :conta_extra_orcamentaria, :orcamento_id, :conta_bancaria, to: :despesa_extra_orcamentaria, allow_nil: true

	attr_default :data_do_estorno, Date.today

	validates_presence_of :data_do_estorno, :justificativa, :despesa_extra_orcamentaria_id
	validates_presence_of :usuario_id

	validates :data_do_estorno, date: true
	validate :valida_data_com_exercicio_logado
	validate :valida_se_ja_houve_envio_do_sim

	before_save :seta_orcamento_do_estorno_de_despesa
	before_save :atribui_codigo_disponivel
	
	before_destroy :desmarca_despesa_extra_orcamentaria_como_estornada

	after_create :estorna_a_despesa_extra_orcamentaria
	after_save :lancar_na_conta_bancaria

	after_save :lancar_movimento_conta_extraorcamentaria

	after_destroy :apagar_movimento_orcamentario_extra
	after_destroy :apagar_movimentos_da_conta_bancaria

	def valor
		return despesa_extra_orcamentaria.valor_total.to_f
	end

	def estorna_a_despesa_extra_orcamentaria
		self.despesa_extra_orcamentaria.update_attribute(:estornada, true) if self.despesa_extra_orcamentaria
	end

	def desmarca_despesa_extra_orcamentaria_como_estornada
		self.despesa_extra_orcamentaria.update_attribute(:estornada, false) if self.despesa_extra_orcamentaria.present?
	end

	def lancar_movimento_conta_extraorcamentaria
		ActiveRecord::Base.transaction do
			valor_despesa = self.valor.to_d
			if valor_despesa > 0
				if self.lancamentos_extraorcamentario_despesa.any?
					self.lancamentos_extraorcamentario_despesa.each do |lancamento|
						apagar_movimento_orcamentario_extra if lancamento.try(:valor) != valor_despesa
					end
				end
				cria_lancamentos_da_conta_extraorcamentaria
			end
		end
	end

	def cria_lancamentos_da_conta_extraorcamentaria
		if despesa_extra_orcamentaria.present? && valor > 0
			valor_despesa =  self.valor.to_d

			movimentacao = Contabilidade::LancamentoExtraorcamentarioDespesa.new(
				conta_extra_orcamentaria_id: self.despesa_extra_orcamentaria.conta_extra_orcamentaria_id,
				data_do_lancamento: self.data_do_estorno,
				valor: valor_despesa * -1,
				modulo: self
			)
			movimentacao.save
		end
	end

	def apagar_movimento_orcamentario_extra
		lancamentos_extraorcamentario_despesa.try(:destroy_all)
	end

	def valida_se_ja_houve_envio_do_sim
		if existe_lote_do_sim?
			errors.add(:data_do_estorno, 'O SIM do mês já foi enviado')
		elsif self.mes_bloqueado?
			errors.add(:data_do_estorno, 'O mês do objeto está bloqueado, solicite o desbloqueio ao administrador')
		end
	end

	def valida_data_com_exercicio_logado
		errors.add(:data_do_estorno, "A data selecionada está fora do exercicio logado") if (self.data_do_estorno.present? && contexto_atual.present? && self.data_do_estorno.year.to_i != contexto_atual.exercicio.to_i)
	end

	def existe_lote_do_sim?
		ultima_data = data_do_estorno

		if ultima_data.present?
			orcamento_id = Orcamento.find_by_exercicio(ultima_data.year)
			lote_sim = Tcm::Lote.find_by(
				orcamento_id: orcamento_id,
				tipo: [Tcm::Lote.tipos[:todos], Tcm::Lote.tipos[:contabilidade]],
				mes_de_referencia: ultima_data.month,
				situacao: [Tcm::Lote.situacoes[:gerado], Tcm::Lote.situacoes[:finalizado]]
			)

			return lote_sim.present?
		end

		return false
	end

	def apagar_movimentos_da_conta_bancaria
		movimentacoes_da_conta = Contabilidade::MovimentacaoDaContaBancaria.where(modulo: self).all
		movimentacoes_da_conta.destroy_all
	end

	def dados_da_movimentacao_bancaria
		{
			conta_bancaria_por_unidade_orcamentaria_id: despesa_extra_orcamentaria.conta_bancaria_por_unidade_orcamentaria.id,
			modulo: self,
			data_da_movimentacao: self.data_do_estorno,
			historico: self.justificativa
		}
	end

	def lancar_na_conta_bancaria
		return false if despesa_extra_orcamentaria.conta_bancaria_por_unidade_orcamentaria.blank?
		
		apagar_movimentos_da_conta_bancaria
		movimentacao = Contabilidade::MovimentacaoDaContaBancaria.find_or_create_by!(dados_da_movimentacao_bancaria)

		if movimentacao.valor.present? && (movimentacao.valor != despesa_extra_orcamentaria.valor_total)
			movimentacao.try(:destroy)
			movimentacao = Contabilidade::MovimentacaoDaContaBancaria.create!(dados_da_movimentacao_bancaria)
		end

		movimentacao.update_attribute(:valor, despesa_extra_orcamentaria.valor_total)
	end

	def to_sim(data_de_referencia, poder_associado)
		begin
			exercicio_do_orcamento = despesa_extra_orcamentaria.orcamento.exercicio.to_s
			conta_bancaria = despesa_extra_orcamentaria.conta_bancaria_por_unidade_orcamentaria.conta_bancaria
			unidade_orcamentaria = despesa_extra_orcamentaria.unidade_orcamentaria
			tipo_de_poder = poder_associado.to_i == 1 ? 1 : 2
			
			texto = ""
			texto << "615".sim_preenche(3) + "," #1
			texto << Configuracao.first.codigo_do_municipio_no_tcm.sim_preenche(3) + "," #2
			texto << exercicio_do_orcamento.sim_limite_sem_aspas(4, "00") + "," #3
			texto << unidade_orcamentaria.orgao.codigo.sim_preenche(2) + "," #4
			texto << unidade_orcamentaria.codigo.codigo_uo_to_sim + "," #5
			texto << despesa_extra_orcamentaria.conta_extra_orcamentaria.codigo_para_o_sim(unidade_orcamentaria.id).to_s + "," #6
			texto << conta_bancaria.agencia.banco.numero_do_banco.to_s.sim_preenche(4) + "," #7
			texto << conta_bancaria.agencia.numero_da_agencia.to_s.delete(".\/-").first(4).sim_preenche(6) + "," #8
			texto << conta_bancaria.numero_da_conta.tr('-', '').tr('.', '').to_s.sim_preenche(10) + "," #9
			texto << despesa_extra_orcamentaria.numero_de_caixa.to_s.sim_limite(10) + "," #10
			texto << data_do_estorno.sim_data + "," #11
			texto << data_de_referencia + "," #12
			texto << Configuracao.last.responsavel_pelo_registro_contabel_atual_PJ(tipo_de_poder).try(:pessoa).try(:nome).to_s.sim_limite(40) + "," #13
			texto << justificativa.to_s.sim_descricao.sim_limite(255) #14
			return texto
		rescue => e
			if e.class.to_s == "NoMethodError"
				atributo_falho = e.message.split(" ")[2]
				coluna = CSV.parse(texto, :headers => false).last.count
				raise e.mensagem_traduzida(self, "", atributo_falho, coluna)
			else
				raise e
			end
		end
	end

	def enviado_ao_sim?
		self.arquivo_id.present? && arquivo.lote.lote_processado_ou_enviado?
	end

	def atribui_codigo_disponivel
		gerar_codigo(send(:data_do_estorno), :numero_do_estorno, :data_do_estorno, :orcamento_id, self.orcamento_id)
	end

	def seta_orcamento_do_estorno_de_despesa
		self.orcamento_id = self.despesa_extra_orcamentaria.orcamento_id
	end
end
