class Loa::Acao < ApplicationRecord
	include VerificacaoDeAlteracaoDeAtributos
	include IncrementadorDeCodigoConcern

	has_paper_trail

	belongs_to :programa_de_governo, required: true
	belongs_to :natureza_da_acao, class_name: 'Base::NaturezaDaAcao', required: true
	belongs_to :iniciativa, class_name: 'Ppa::Iniciativa'
	belongs_to :solicitacao_de_alteracao_orcamentaria, class_name: 'Contabilidade::SolicitacaoDeAlteracaoOrcamentaria'

	has_many :subacoes, inverse_of: :acao
	has_many :elementos_de_despesa, through: :subacoes
	has_many :orcamentos_da_despesa, through: :subacoes
	has_many :dotacoes_origem, through: :solicitacao_de_alteracao_orcamentaria
	has_many :dotacoes_destino, through: :solicitacao_de_alteracao_orcamentaria

	accepts_nested_attributes_for :subacoes, allow_destroy: true

	validates_associated :subacoes

	after_initialize :sugestao_de_codigo, if: :new_record?

	before_destroy :verifica_dependencia_subacao
	before_destroy :valida_apagar_acao

	validates_presence_of :programa_de_governo_id
	validates_presence_of :natureza_da_acao_id
	validates_presence_of :nome
	validates_presence_of :codigo
	validates_presence_of :status_do_orcamento

	validates_length_of :codigo, is: 3
	validates_length_of :nome, maximum: 120
	validates_length_of :descricao, maximum: 255

	validates_uniqueness_of :codigo, scope: [:natureza_da_acao_id]
	validates_uniqueness_of :nome, scope: [:programa_de_governo_id, :natureza_da_acao_id, :codigo]

	scope :operacoes_especiais,      -> { joins(:natureza_da_acao).where('base_naturezas_das_acoes.codigo = ?', '0') }
	scope :projetos,                 -> { joins(:natureza_da_acao).where('base_naturezas_das_acoes.codigo = ?', '1') }
	scope :atividades,               -> { joins(:natureza_da_acao).where('base_naturezas_das_acoes.codigo = ?', '2') }
	scope :reservas_de_contingencia, -> { joins(:natureza_da_acao).where('base_naturezas_das_acoes.codigo = ?', '9') }

	enum status_do_orcamento: STATUS_DO_ORCAMENTO

	ransacker :codigo_completo do
		Arel.sql("base_naturezas_das_acoes.codigo::text ||'.'|| LPAD(loa_acoes.codigo::text, 3, '0')")
	end

	ransacker :nome do
		Arel.sql("loa_acoes.nome::text")
	end

	def importado_do_ppa?
		self.iniciativa_id.present?
	end

	def reserva_de_contingencia?
		natureza_da_acao.try(:codigo) == '9'
	end

	def subacao
		subacoes.first unless trabalha_com_subacao?
	end

	def codigo_e_nome
		"#{codigo_completo} - #{nome}"
	end

	def codigo_completo
		"#{self.natureza_da_acao.try(:codigo)}.#{codigo}"
	end

	def codigo_completo_sem_ponto
		"#{self.natureza_da_acao.try(:codigo)}#{codigo}"
	end

	def codigo_e_descricao
		"#{self.codigo_completo} - #{self.nome}"
	end

	def valor_total_fixado_da_despesa
		if solicitacao_de_alteracao_orcamentaria.present?
			self.subacoes.inject(0) { |total, subacao| total + subacao.valor_total_fixado_da_despesa.to_f}
		else
			self.subacoes.inject(0) { |total, subacao| total + subacao.fixacao_da_despesa.to_f}
		end
	end

	def valida_apagar_acao
		if total_da_despesa > 0
			raise ActiveRecord::DeleteRestrictionError.new "ação não pode ser apagada, valor total fixado da despesa maior que 0."
		end
	end

	def total_da_despesa
		self.subacoes.inject(0) { |total, subacao| total + subacao.valor_total_fixado_da_despesa.to_f}
	end
	

	def valor_total_realizado_da_despesa
		self.subacoes.inject(0) { |total, subacao|
			total + subacao.valor_total_realizado_da_despesa.to_f
		}
	end

	def self.sugestao_de_codigo natureza_da_acao_id
		codigos_utilizados = ::Loa::Acao.where(
			natureza_da_acao_id: natureza_da_acao_id
			).order( :codigo ).pluck( :codigo ).map { |codigo|
			codigo.to_i
		}
		return 1.digitos(3) if codigos_utilizados.empty?
		codigos_disponiveis = (1..codigos_utilizados.last.to_i + 1).to_a - codigos_utilizados
		codigos_disponiveis.first.digitos(3)
	end

	def importar_dados_da_iniciativa
		if self.programa_de_governo.present?
			orcamento = self.programa_de_governo.orcamento
			ppa_iniciativa = Ppa::Iniciativa.find(self.iniciativa_id)
			if ppa_iniciativa
				self.codigo = ppa_iniciativa.codigo_com_zeros
				self.nome = ppa_iniciativa.descricao[0..119]
				self.descricao = ppa_iniciativa.descricao[0..254]
				self.natureza_da_acao_id = orcamento.naturezas_da_acao.find_by(codigo: ppa_iniciativa.natureza_da_iniciativa.codigo).id
				subacao = self.subacoes.new
				subacao.atribui_codigo_da_subacao if subacao.present?
				subacao.unidade_orcamentaria = ppa_iniciativa.unidade_orcamentaria.loa_unidades_orcamentarias.joins(:orgao).find_by( loa_orgaos: {orcamento_id: orcamento.id}) if ppa_iniciativa.unidade_orcamentaria.present?
				subfuncao = Base::Subfuncao.joins(:funcao).find_by(codigo: ppa_iniciativa.sub_funcao.try(:codigo), base_funcoes: {modulo_id: self.programa_de_governo.orcamento.id})
				if subfuncao.present?
					subacao.subfuncao_id = subfuncao.id
					subacao.funcao_id = subfuncao.funcao.id
					subacao.tipo_de_orcamento_id = subfuncao.funcao.tipo_de_orcamento_id
				end
			end
		end
	end

	def trabalha_com_subacao?
		programa_de_governo.orcamento.trabalha_com_subacao?
	end
	
	private
	def sugestao_de_codigo
		gerar_sugestao_codigo( :codigo, 3, {programa_de_governo_id: programa_de_governo.id} ) if (programa_de_governo.present? && codigo.blank?)
	end

	def verifica_dependencia_subacao
		if trabalha_com_subacao? && subacoes.any?
			raise ActiveRecord::DeleteRestrictionError.new "Não é possivel deletar ação pois essa possui subações relacionadas"
			return false
		else
			subacoes.destroy_all
		end
	end
end
