class Ppa::ProjecaoDeDespesa < ApplicationRecord
	include CalculaDespesasDoPrograma
	include GeradorDeEventosContabeis

	has_paper_trail

	attr_default :valor, 0.00

	belongs_to :orcador, polymorphic: true
	belongs_to :tipo_de_despesa, class_name: "Base::TipoDeDespesa"
	belongs_to :unidade_orcamentaria

	validates_presence_of :orcador_id, :unidade_orcamentaria_id, :exercicio, :valor, :tipo_de_despesa_id
	validates_numericality_of :valor, greater_than_or_equal_to: 0
	validates :orcador_id, :orcador_type, :exercicio, :tipo_de_despesa_id, immutable: true

	validates_uniqueness_of :exercicio, scope: [:orcador_id, :orcador_type, :unidade_orcamentaria_id, :tipo_de_despesa_id]

	validate :esta_dentro_do_periodo_do_ppa
	validate :tem_a_mesma_unidade_orcamentaria_da_iniciativa, if: :pertence_a_uma_iniciativa?

	def self.recurso_por_programas_tematicos ppa_id
		joins("JOIN ppa_programas ON ppa_projecoes_de_despesa.orcador_id = ppa_programas.id
			JOIN ppa_tipos_de_programa ON ppa_tipos_de_programa.id = ppa_programas.tipo_de_programa_id")
			.where.not('ppa_tipos_de_programa.codigo = 2')
			.where('ppa_projecoes_de_despesa.orcador_type = ? AND ppa_programas.ppa_id = ?', "Ppa::Programa", ppa_id)
			.includes(:orcador).group_by {|projecao_despesa| projecao_despesa.orcador.nome}.map { |nome_programa, valor_projecao|
				{
					nome: nome_programa.to_s,
					quantidade: valor_projecao.inject(0){|total, projecao_despesa| total + projecao_despesa.valor}.to_f
				}
			}.delete_if {|x| x[:quantidade] == 0}
	end

	def self.recursos_por_tipo_de_programa ppa_id
		joins("JOIN ppa_programas ON ppa_projecoes_de_despesa.orcador_id = ppa_programas.id").
		where('ppa_projecoes_de_despesa.orcador_type = ? AND ppa_programas.ppa_id = ?', "Ppa::Programa", ppa_id).
		group_by {|projecao| projecao.orcador.tipo_de_programa.nome}.map { |nome_tipo_programa, projecoes_de_despesa|
			{
				nome: nome_tipo_programa.to_s,
				quantidade: projecoes_de_despesa.inject(0){|total, projecao| total + projecao.valor}
			}
		}
	end

	def self.recurso_por_funcao_de_despesa ppa_id
		joins("JOIN ppa_iniciativas ON ppa_projecoes_de_despesa.orcador_id = ppa_iniciativas.id").
		joins("JOIN ppa_funcoes ON ppa_funcoes.id = ppa_iniciativas.funcao_id").
		where('ppa_projecoes_de_despesa.orcador_type = ? AND ppa_funcoes.ppa_id = ?', "Ppa::Iniciativa", ppa_id).
		group_by {|projecao| projecao.orcador.funcao.nome}.map { |nome_fonte_despesa, projecao_de_despesa|
			{
				nome: nome_fonte_despesa.to_s,
				quantidade: projecao_de_despesa.inject(0){|total, projecao| total + projecao.valor }
			}
		}
	end

	def self.despesas_correntes
		where( tipo_de_despesa_id: Base::TipoDeDespesa.despesa_corrente.id )
	end

	def self.despesas_de_capital
		where( tipo_de_despesa_id: Base::TipoDeDespesa.despesa_de_capital.id )
	end

	private
	def pertence_a_uma_iniciativa?
		orcador_type.try(:constantize) == Ppa::Iniciativa
	end

	def pertence_a_um_programa?
		orcador_type.try(:constantize).constantize == Ppa::Programa
	end

	def esta_dentro_do_periodo_do_ppa
		errors[:exercicio] << 'deve estar dentro do período do PPA' unless orcador.present? && orcador.ppa.periodo.include?(self.exercicio)
	end

	def tem_a_mesma_unidade_orcamentaria_da_iniciativa
		unless unidade_orcamentaria_id == orcador.unidade_orcamentaria_id
			errors[:unidade_orcamentaria_id] << 'deve ser igual a unidade orçamentária da iniciativa da iniciativa'
		end
	end
end
