class Loa::OrcamentoDaReceita < ApplicationRecord
	include GeradorDeEventosContabeis
	attr_accessor :porcentagem
	attr_accessor :ativo

	has_paper_trail

	attr_default :porcentagem, 0.00
	attr_default :valor_atual, 0.00
	attr_default :forma_de_adicao, :original
	attr_default :valor_arrecadado, 0.00

	belongs_to :fonte_de_recursos, class_name: 'Base::FonteDeRecursos', required: true
	belongs_to :unidade_orcamentaria_por_natureza_da_receita, required: true, inverse_of: :orcamentos_da_receita
	has_many :lancamentos_do_orcamento_da_receita, class_name: 'Contabilidade::LancamentoDoOrcamentoDaReceita', dependent: :destroy
	has_many :balancetes_de_receita_orcamentaria, class_name: 'Loa::BalanceteDeReceitaOrcamentaria'

	delegate :unidade_orcamentaria, to: :unidade_orcamentaria_por_natureza_da_receita, allow_nil: true
	delegate :natureza_da_receita, to: :unidade_orcamentaria_por_natureza_da_receita, allow_nil: true

	enum status_do_orcamento: STATUS_DO_ORCAMENTO

	validates_presence_of :fonte_de_recursos_id, :valor, :unidade_orcamentaria_por_natureza_da_receita, :status_do_orcamento
	validates_numericality_of :valor, greater_than: 0, unless: :receita_permite_valor_negativo, if: Proc.new{ self.persisted? }
	validates_numericality_of :valor_atual, greater_than: 0, if: Proc.new { self.revisado? }

	validates_uniqueness_of :fonte_de_recursos_id, scope: :unidade_orcamentaria_por_natureza_da_receita_id, if: Proc.new{ self.persisted? }

	validate :valor_negativo_para_deducoes_de_receita, if: Proc.new{ natureza_da_receita.present? }

	scope :fiscal, -> { joins(unidade_orcamentaria_por_natureza_da_receita:[natureza_da_receita: :tipo_de_orcamento]).where("base_tipos_de_orcamento.numero =?", '1') }
	scope :social, -> { joins(unidade_orcamentaria_por_natureza_da_receita:[natureza_da_receita: :tipo_de_orcamento]).where("base_tipos_de_orcamento.numero =?", '2') }
	scope :ordenado_por_natureza, -> { includes(unidade_orcamentaria_por_natureza_da_receita: :natureza_da_receita).order('base_naturezas_da_receita.codigo') }

	after_create :torna_valor_da_deducao_negativa

	enum forma_de_adicao: { original: 1, revisado: 2	}

	def torna_valor_da_deducao_negativa
		if self.unidade_orcamentaria_por_natureza_da_receita != nil
			if self.unidade_orcamentaria_por_natureza_da_receita.natureza_da_receita.categoria_economica.to_i >= 900 && self.valor.to_f > 0
					self.valor = self.valor.to_f * (-1)
					self.save(validate: false)
			end
		end
	end

	def codigo_e_descricao_fonte
		fonte_de_recursos ? fonte_de_recursos.codigo_e_descricao : ""
	end

	def saldo
		if natureza_da_receita.present? && natureza_da_receita.deducao?
			self.valor.to_f + self.valor_arrecadado.to_f
		else
			self.valor.to_f - self.valor_arrecadado.to_f
		end
	end
	
	def saldo_previsao
		if self.valor_atual > 0 && self.valor_atual != self.valor
			self.valor - self.valor_atual
		else
			0
		end
	end

	def valor_total
		self.unidade_orcamentaria_por_natureza_da_receita.valor_total
	end

	def percentual_do_arrecadado_sobre_o_valor_orcado
		if self.valor.abs.to_f > 0
			((self.valor_arrecadado.to_f * 100) / self.valor.abs.to_f).round(2)
		else
			self.valor_arrecadado.to_f.round(2)
		end
	end

	def valor_negativo_para_deducoes_de_receita
		if !receita_permite_valor_negativo && self.valor.to_f < 0.0
			errors.add(:valor, "valores negativos só são permitidos para classificações: 9.5.X.X.XX.XX.XX (deduções da receita)")
		end
	end

	def atualiza_saldo_dos_lancamentos
		saldo_atual = self.valor.to_f
		self.lancamentos_do_orcamento_da_receita.order("data_do_lancamento asc", "created_at asc").each do |lancamento|
			saldo_atual = saldo_atual - lancamento.valor.to_f
			lancamento.update(saldo: saldo_atual)
		end
	end

	def natureza_da_receita
		if unidade_orcamentaria_por_natureza_da_receita.present?
			unidade_orcamentaria_por_natureza_da_receita.natureza_da_receita
		end
	end

	def classificacao_da_receita
		unidade_orcamentaria_por_natureza_da_receita.try(:natureza_da_receita).try(:classificacao).try(:formatar_comeco_sem_zero)
	end

	def to_sim
		begin
			texto = ""
			texto << "201".to_s.sim_preenche(3) + ","
			texto << Configuracao.first.codigo_do_municipio_no_tcm.to_s.sim_preenche(3) + ","
			texto << unidade_orcamentaria_por_natureza_da_receita.unidade_orcamentaria.orgao.orcamento.exercicio.to_s.sim_limite_sem_aspas(4, "00") + ","
			texto << unidade_orcamentaria_por_natureza_da_receita.unidade_orcamentaria.orgao.codigo.to_s.sim_limite(2) + "," #Código do Órgão
			texto << unidade_orcamentaria_por_natureza_da_receita.unidade_orcamentaria.codigo.to_s.codigo_uo_to_sim + "," #Código da Unidade Orçamentária
			texto << (unidade_orcamentaria_por_natureza_da_receita.natureza_da_receita.codigo.to_s.last(-2) + '0').sim_preenche_a_direita(15) + "," #Código da Receita Orçamentária
			texto << fonte_de_recursos.codigo_completo.to_s.sim_limite(1) + "," #Código do Grupo da Fonte

			codigo_da_fonte_de_recurso =  fonte_de_recursos.try(:codigo_completo).to_s
			codigo_da_fonte_de_recurso.try(:slice!, 0)
			texto << codigo_da_fonte_de_recurso.to_s.sim_limite(9) + "," #8

			texto << unidade_orcamentaria_por_natureza_da_receita.natureza_da_receita.descricao.to_s.sim_limite(120) + "," #Descrição do Detalhamento da Receita Orçamentária
			if self.valor_atual > 0
				texto << valor_atual.to_f.to_s.sim_valor
			else
				texto << valor.to_f.to_s.sim_valor
			end
	
			return texto
		end
		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

	def valor_das_anulacoes_mes(data)
		tipo = Contabilidade::AnulacaoDoTalaoDeReceita
		anulacoes = self.lancamentos_do_orcamento_da_receita.joins("left join contabilidade_anulacoes_dos_taloes_de_receita on contabilidade_anulacoes_dos_taloes_de_receita.id = contabilidade_lancamentos_do_orcamento_da_receita.modulo_id and contabilidade_lancamentos_do_orcamento_da_receita.modulo_type = '#{tipo}' left join contabilidade_taloes_de_receita on contabilidade_taloes_de_receita.id = contabilidade_anulacoes_dos_taloes_de_receita.talao_de_receita_id").where("contabilidade_taloes_de_receita.talao_de_desconto is false").where('data_do_lancamento >=  ?', data).where('data_do_lancamento < ?', data + 1.months)
		anulacoes.map { |a| a.valor.abs }.sum
	end

	def valor_das_anulacoes_periodo(data)
		tipo = Contabilidade::AnulacaoDoTalaoDeReceita
		anulacoes = self.lancamentos_do_orcamento_da_receita.joins("left join contabilidade_anulacoes_dos_taloes_de_receita on contabilidade_anulacoes_dos_taloes_de_receita.id = contabilidade_lancamentos_do_orcamento_da_receita.modulo_id and contabilidade_lancamentos_do_orcamento_da_receita.modulo_type = '#{tipo}' left join contabilidade_taloes_de_receita on contabilidade_taloes_de_receita.id = contabilidade_anulacoes_dos_taloes_de_receita.talao_de_receita_id").where("contabilidade_taloes_de_receita.talao_de_desconto is false").where('data_do_lancamento < ?', data + 1.months)

		anulacoes.map { |a| a.valor.abs }.sum
	end

	def valor_arrecadado_mes(data)
		tipo = "Contabilidade::TalaoDeReceita"
		arrecadacoes = self.lancamentos_do_orcamento_da_receita.joins("left join contabilidade_taloes_de_receita on contabilidade_taloes_de_receita.id = contabilidade_lancamentos_do_orcamento_da_receita.modulo_id and contabilidade_lancamentos_do_orcamento_da_receita.modulo_type = 'Contabilidade::TalaoDeReceita'").where('modulo_type = ?' , tipo).where('data_do_lancamento >=  ?', data).where('data_do_lancamento < ?', data + 1.months)

		arrecadacoes.sum(&:valor)
	end

	def valor_arrecadado_periodo(data)
		tipo = "Contabilidade::TalaoDeReceita"
		arrecadacoes = self.lancamentos_do_orcamento_da_receita.joins("left join contabilidade_taloes_de_receita on contabilidade_taloes_de_receita.id = contabilidade_lancamentos_do_orcamento_da_receita.modulo_id and contabilidade_lancamentos_do_orcamento_da_receita.modulo_type = 'Contabilidade::TalaoDeReceita'").where('modulo_type = ?' , tipo).where('data_do_lancamento < ?', data + 1.months)

		arrecadacoes.sum(&:valor)
	end

	def valor_arrecadado_periodo_inicial_final(data_inicio, data_fim)
		tipo = "Contabilidade::TalaoDeReceita"
		arrecadacoes = self.lancamentos_do_orcamento_da_receita.where('data_do_lancamento >= ? and data_do_lancamento <= ?', data_inicio, data_fim)

		return arrecadacoes.sum(&:valor)
	end

	def to_sim_balancetes_de_receitas_orcamentarias(data_referencia)
		begin
		texto = ""
		texto << "301".to_s.sim_preenche(3) + "," #1
		texto << Configuracao.first.codigo_do_municipio_no_tcm.to_s.sim_preenche(3) + "," #2
		texto << unidade_orcamentaria_por_natureza_da_receita.unidade_orcamentaria.orgao.orcamento.exercicio.to_s.sim_limite_sem_aspas(4, "00") + "," #3
		texto << unidade_orcamentaria_por_natureza_da_receita.unidade_orcamentaria.orgao.codigo.sim_limite(2) + "," #4
		texto << unidade_orcamentaria_por_natureza_da_receita.unidade_orcamentaria.codigo.codigo_uo_to_sim + "," #5
		texto << (unidade_orcamentaria_por_natureza_da_receita.natureza_da_receita.codigo.to_s.last(-2) + '0').sim_preenche_a_direita(15) + "," #6
		texto << fonte_de_recursos.codigo_completo.sim_limite(1) + ","#7 tem que ser ajutado
		texto << fonte_de_recursos.codigo_completo.to_s[1..10].sim_limite(9)+ ","#8
		texto << data_referencia.sim_data.sim_limite_sem_aspas(6) + ","#9
		texto << '"G"'+ "," #10   Lukas falou que sempre iria ser "G"
		texto << valor.to_s.sim_valor + "," #11
		texto << (valor_das_anulacoes_mes(data_referencia) != 0 ? valor_das_anulacoes_mes(data_referencia).to_s.sim_valor : "0.00") + ","#12
		texto << (valor_das_anulacoes_periodo(data_referencia) != 0 ? valor_das_anulacoes_periodo(data_referencia).to_s.sim_valor : "0.00") + ","#13
		texto << (valor_arrecadado_mes(data_referencia) != 0 ? valor_arrecadado_mes(data_referencia).to_s.sim_valor : "0.00") + "," #14
		texto << (valor_arrecadado_periodo(data_referencia) != 0 ? valor_arrecadado_periodo(data_referencia).to_s.sim_valor : "0.00") #15

		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, self.id, atributo_falho, coluna)
			else
				raise e
			end
		end
	end

	private
	def receita_permite_valor_negativo
		if natureza_da_receita.tipo_de_alteracao.present?
			(natureza_da_receita.present? && natureza_da_receita.deducao? || natureza_da_receita.present? && natureza_da_receita.tipo_de_alteracao == "nova_ug")
		else
			natureza_da_receita.present? && natureza_da_receita.deducao?
		end
	end

end
