class Ppa::Iniciativa < ApplicationRecord
	has_paper_trail

	belongs_to :objetivo
	belongs_to :funcao
	belongs_to :sub_funcao
	belongs_to :natureza_da_iniciativa
	belongs_to :unidade_orcamentaria
	belongs_to :proposta

	has_many :projecoes_de_despesa, as: :orcador, dependent: :destroy

	after_create :cria_projecoes_de_despesa_para_cada_exercicio, if: :ppa_detalha_despesas_nas_iniciativas?

	before_create :atualiza_status_da_proposta_escolhida
	after_save :ajusta_as_projecoes_de_despesas_para_o_programa!, if: :ppa_detalha_despesas_no_programa?
	before_update  :atualiza_status_da_proposta_escolhida
	after_update :atualiza_unidades_orcamentarias_das_projecoes_de_despesa, if: :ppa_detalha_despesas_nas_iniciativas?
	before_destroy  :atualiza_status_da_proposta_escolhida
	after_destroy :apaga_as_projecoes_de_despesa_do_programa, if: :ppa_detalha_despesas_no_programa?

	validates_presence_of :descricao, :objetivo_id, :funcao_id,
		:sub_funcao_id, :natureza_da_iniciativa_id, :unidade_orcamentaria_id

	validates_uniqueness_of :descricao, scope: :objetivo_id
	validates_uniqueness_of :proposta_id, if: Proc.new{ |proposta| proposta.proposta_id.present? }

	validate :unicidade_do_codigo
	validate :unidade_orcamentaria_deve_pertencer_ao_mesmo_ppa

	accepts_nested_attributes_for :projecoes_de_despesa

	def ppa
		objetivo.programa.ppa
	end

	def programa
		objetivo.programa
	end

	class << self
		def sugestao_de_codigo_para_a_proxima_iniciativa( ppa_id, natureza_da_iniciativa_id )
			ultimo_codigo = Ppa::Ppa.joins( programas:[objetivos: :iniciativas ])
				.where( id: ppa_id )
				.where('ppa_iniciativas.natureza_da_iniciativa_id = ?', natureza_da_iniciativa_id )
				.maximum('ppa_iniciativas.codigo')

			ultimo_codigo.try(:next) || 1
		end
	end

	def codigo_com_zeros
		codigo.try(:digitos, 3)
	end

	def codigo_completo
		"#{natureza_da_iniciativa.try(:codigo)}#{codigo_com_zeros}"
	end

	def despesas_correntes
		self.projecoes_de_despesa.joins(:tipo_de_despesa).where('base_tipos_de_despesa.codigo = 1')
	end

	def despesas_de_capital
		self.projecoes_de_despesa.joins(:tipo_de_despesa).where('base_tipos_de_despesa.codigo = 2')
	end

	private
	def atualiza_status_da_proposta_escolhida
		if self.proposta.present?
			proposta_escolhida = Ppa::Proposta.find( proposta_id )
			proposta_escolhida.regiao_id = proposta_escolhida.micro_regiao.regiao_id if proposta_escolhida.regiao_id.blank?
			proposta_escolhida.update(status: 'lancada_no_ppa')
		end
	end

	def unicidade_do_codigo
		if objetivo_id.present? && natureza_da_iniciativa_id.present? && codigo.present?
			iniciativas_do_mesmo_ppa = Ppa::Iniciativa.joins(objetivo: [ programa: :ppa ] ).where( 'ppa_ppas.id = ?', ppa.id )
			iniciativa_igual = iniciativas_do_mesmo_ppa.find_by( natureza_da_iniciativa_id: natureza_da_iniciativa_id, codigo: codigo )
			if iniciativa_igual.present? && iniciativa_igual.id != self.id
				errors[:codigo] << 'já está em uso'
			end
		end
	end

	def unidade_orcamentaria_deve_pertencer_ao_mesmo_ppa
		if objetivo_id.present? && unidade_orcamentaria.present?
			unless ppa.id == unidade_orcamentaria.orgao.ppa.id
				errors[:unidade_orcamentaria_id] << 'deve pertencer ao mesmo PPA'
			end
		end
	end

	def ajusta_as_projecoes_de_despesas_para_o_programa!
		apaga_projecoes_de_despesa_do_programa_da_unidade_orcamentaria_antiga
		cria_projecoes_de_despesa_do_programa_da_unidade_orcamentaria
	end

	def  apaga_projecoes_de_despesa_do_programa_da_unidade_orcamentaria_antiga
		if iniciativas_do_mesmo_programa_com_a_unidade_orcamentaria( unidade_orcamentaria_antiga ).empty?
			projecoes_de_despesa_do_programa_da_unidade_orcamentaria( unidade_orcamentaria_antiga ).destroy_all
		end
	end

	def cria_projecoes_de_despesa_do_programa_da_unidade_orcamentaria
		if projecoes_de_despesa_do_programa_da_unidade_orcamentaria( unidade_orcamentaria_id ).empty?
			cria_projecoes_de_despesa_para_cada_exercicio
		end
	end

	def iniciativas_do_mesmo_programa_com_a_unidade_orcamentaria( unidade_orcamentaria_id )
		programa.iniciativas.where.not( id: id ).where( unidade_orcamentaria_id: unidade_orcamentaria_id )
	end

	def projecoes_de_despesa_do_programa_da_unidade_orcamentaria( unidade_orcamentaria_id )
		programa.projecoes_de_despesa.where( unidade_orcamentaria_id: unidade_orcamentaria_id )
	end

	def cria_projecoes_de_despesa_para_cada_exercicio
		if ppa.exercicio_inicial.present? && ppa.exercicio_final.present?
			for exercicio in ppa.exercicio_inicial..ppa.exercicio_final
				cria_projecao_de_despesa( Base::TipoDeDespesa.despesa_corrente, exercicio )
				cria_projecao_de_despesa( Base::TipoDeDespesa.despesa_de_capital, exercicio )
			end
		end
	end

	def cria_projecao_de_despesa( tipo_de_despesa, exercicio )
		if ppa.detalha_despesas_nas_iniciativas?
			self.projecoes_de_despesa.create!(
				exercicio: exercicio,
				unidade_orcamentaria_id: unidade_orcamentaria_id,
				tipo_de_despesa_id: tipo_de_despesa.id,
				valor: 0
			)
		else
			programa.projecoes_de_despesa.create!(
				exercicio: exercicio,
				unidade_orcamentaria_id: unidade_orcamentaria_id,
				tipo_de_despesa_id: tipo_de_despesa.id,
				valor: 0
			)
		end
	end

	def apaga_as_projecoes_de_despesa_do_programa
		if iniciativas_do_mesmo_programa_com_a_unidade_orcamentaria( unidade_orcamentaria_id ).empty?
			projecoes_de_despesa_do_programa_da_unidade_orcamentaria( unidade_orcamentaria_id ).destroy_all
		end
	end

	def atualiza_unidades_orcamentarias_das_projecoes_de_despesa
		projecoes_de_despesa.update_all( unidade_orcamentaria_id: unidade_orcamentaria_id )
		programa.projecoes_de_despesa.update_all( unidade_orcamentaria_id: unidade_orcamentaria_id )
	end

	def ppa_detalha_despesas_no_programa?
		not ppa.detalha_despesas_nas_iniciativas?
	end

	def ppa_detalha_despesas_nas_iniciativas?
		ppa.detalha_despesas_nas_iniciativas?
	end

	def unidade_orcamentaria_antiga
		changes["unidade_orcamentaria_id"].try(:first)
	end
end
