require 'active_support/concern'

module CalculaDespesasDoPrograma
	extend ActiveSupport::Concern

	def projecoes_de_despesa_organizadas
		resultado = {}

		resultado['orgaos'] = orgaos_formatados( dados_das_projecoes_de_despesa  )

		resultado['resumo'] = totalizar( resultado['orgaos'] )

		resultado
	end

	private
	def dados_das_projecoes_de_despesa
		ActiveRecord::Base.connection.execute( sql_de_todas_as_projecoes_de_despesas )
	end

	def orgaos_formatados( despesas )
		orgaos = []

		despesas_agrupadas_por_orgao = despesas.group_by do |despesa|
			despesa["orgao_codigo"]
		end

		despesas_agrupadas_por_orgao.each_value do |despesas|
			orgaos << orgao_formatado( despesas )
		end

		orgaos
	end

	def orgao_formatado( despesas )
		orgao = {}

		orgao['codigo'] =despesas.first['orgao_codigo'].to_i.digitos(2)
		orgao['nome'] = despesas.first['orgao_nome']
		orgao['sigla'] = despesas.first['orgao_sigla']
		orgao['unidades-orcamentarias'] = unidades_orcamentarias_formatadas( despesas )
		orgao['despesas'] = calcula_despesas_do_orgao( orgao['unidades-orcamentarias']  )
		orgao
	end

	def unidades_orcamentarias_formatadas( despesas )
		unidades_orcamentarias = []

		despesas_agrupadas_por_unidade_orcamentaria = despesas.group_by do |despesa|
			despesa['unidade_orcamentaria_codigo']
		end

		despesas_agrupadas_por_unidade_orcamentaria.each_value do |despesas|
			unidades_orcamentarias << unidade_orcamentaria_formatada( despesas )
		end

		unidades_orcamentarias
	end

	def unidade_orcamentaria_formatada( despesas )
		unidade_orcamentaria = {}

		unidade_orcamentaria['codigo'] = despesas.first['unidade_orcamentaria_codigo'].to_i.digitos( 2 )
		unidade_orcamentaria['nome'] = despesas.first['unidade_orcamentaria_nome']
		unidade_orcamentaria['sigla'] = despesas.first['unidade_orcamentaria_sigla']
		unidade_orcamentaria['despesas'] = projecoes_de_despesa_formatadas( despesas )

		unidade_orcamentaria
	end

	def projecoes_de_despesa_formatadas( despesas )
		projecoes_de_despesa_formatadas = []

		despesas_agrupadas_por_exercicio = despesas.group_by do |despesa|
			despesa['exercicio']
		end

		despesas_agrupadas_por_exercicio.each_value do |despesas|
			projecoes_de_despesa_formatadas << projecao_de_despesa_formatada( despesas )
		end

		projecoes_de_despesa_formatadas
	end

	def projecao_de_despesa_formatada( despesas )
		projecao_de_despesa = {}

		despesa_corrente = despesas.find{|despesa| despesa['tipo_de_despesa'] == 'Despesa Corrente' }
		despesa_de_capital = despesas.find{|despesa| despesa['tipo_de_despesa'] == 'Despesa de Capital' }
		valor_despesa_corrente = despesa_corrente['valor'].to_d
		valor_despesa_de_capital = despesa_de_capital['valor'].to_d

		projecao_de_despesa['exercicio'] = despesas.first['exercicio']
		projecao_de_despesa['despesa-corrente'] = valor_despesa_corrente
		projecao_de_despesa['despesa-de-capital'] = valor_despesa_de_capital
		projecao_de_despesa['total'] = valor_despesa_corrente+ valor_despesa_de_capital

		projecao_de_despesa
	end

	def calcula_despesas_do_orgao( unidades_orcamentarias )
		despesas = []
		unidades_orcamentarias.each do |unidade_orcamentaria|
			unidade_orcamentaria['despesas'].each do |despesa_uo|
				despesa = retorna_total_pelo_exercicio( despesas, despesa_uo['exercicio'] )
			 	despesa['despesa-corrente'] += despesa_uo['despesa-corrente']
				despesa['despesa-de-capital'] += despesa_uo['despesa-de-capital']
				despesa['total'] += despesa_uo['total']
			end
		end
		despesas
	end

	def totalizar( despesas_organizadas )
		resumo = {}
		resumo['totais'] = []
		resumo['total-geral'] = 0

		despesas_organizadas.each do |orgao|
			orgao['unidades-orcamentarias'].each do |unidade_orcamentaria|
				unidade_orcamentaria['despesas'].each do |despesa|
					total = retorna_total_pelo_exercicio( resumo['totais'], despesa['exercicio' ])
					total['despesa-corrente'] += despesa['despesa-corrente']
					total['despesa-de-capital'] += despesa['despesa-de-capital']
					total['total'] += despesa['total']
					resumo['total-geral'] += despesa['total']
				end
			end
		end

		resumo
	end

	def retorna_total_pelo_exercicio( totais, exercicio )
		total = totais.find{ |total| total['exercicio'] == exercicio }
		if total.nil?
			total = {
				"exercicio" => exercicio,
				"despesa-corrente" => 0,
				"despesa-de-capital" => 0,
				"total" => 0
			}
			totais << total
		end
		total
	end

	def consolida_tres_ultimos_exercicios( despesas_organizadas )
		despesas_organizadas.each do |orgao|
			orgao['unidades-orcamentarias'].each do |unidade_orcamentaria|
				tres_ultimos_exercicios = unidade_orcamentaria['despesas'].slice!( -3..-1 )

				consolidacao = {
					"exercicio" => "#{tres_ultimos_exercicios.first['exercicio']} - #{tres_ultimos_exercicios.last['exercicio']}",
					"despesa-corrente" => 0,
					"despesa-de-capital" => 0,
					"total" => 0
				}

				tres_ultimos_exercicios.each do |despesa|
					consolidacao['despesa-corrente'] += despesa['despesa-corrente']
					consolidacao['despesa-de-capital'] += despesa['despesa-de-capital']
					consolidacao['total'] += despesa['total']
				end

				unidade_orcamentaria['despesas'] << consolidacao
			end

			orgao['despesas'] = calcula_despesas_do_orgao( orgao['unidades-orcamentarias'])
		end
	end

	def sql_de_todas_as_projecoes_de_despesas
		%Q(
		SELECT
			orgao.codigo as orgao_codigo,
			orgao.nome as orgao_nome,
			orgao.sigla as orgao_sigla,
			unidade_orcamentaria.codigo as unidade_orcamentaria_codigo,
			unidade_orcamentaria.nome as unidade_orcamentaria_nome,
			unidade_orcamentaria.sigla as unidade_orcamentaria_sigla,
			projecao.exercicio,
			tipo_de_despesa.descricao as tipo_de_despesa,
			SUM( projecao.valor ) as valor
		FROM ppa_projecoes_de_despesa as projecao
		#{join_com_programa}
		JOIN ppa_unidades_orcamentarias as unidade_orcamentaria ON unidade_orcamentaria.id = projecao.unidade_orcamentaria_id
		JOIN ppa_orgaos as orgao ON orgao.id = unidade_orcamentaria.orgao_id
		JOIN base_tipos_de_despesa as tipo_de_despesa ON tipo_de_despesa.id = projecao.tipo_de_despesa_id
		WHERE programa.id = #{id}
		  AND #{where_programa}
		GROUP BY
			orgao_codigo,
			orgao_nome,
			orgao_sigla,
			unidade_orcamentaria_codigo,
			unidade_orcamentaria_nome,
			unidade_orcamentaria_sigla,
			projecao.exercicio,
			tipo_de_despesa
		ORDER BY
			orgao_codigo,
			unidade_orcamentaria_codigo,
			projecao.exercicio,
			tipo_de_despesa
		)
	end

	def join_com_programa
		if ppa.detalha_despesas_nas_iniciativas?
			join_programa_atraves_das_iniciativas
		else
			join_com_programa_diretamente
		end
	end

	def where_programa
		if ppa.detalha_despesas_nas_iniciativas?
			%Q(
				projecao.orcador_type = 'Ppa::Iniciativa'
			)
		else
			%Q(
				projecao.orcador_type = 'Ppa::Programa'
			)
		end
	end

	def join_programa_atraves_das_iniciativas
		%Q(
			JOIN ppa_iniciativas as iniciativa ON projecao.orcador_id = iniciativa.id
			JOIN ppa_objetivos as objetivo ON objetivo.id = iniciativa.objetivo_id
			JOIN ppa_programas as programa ON programa.id = objetivo.programa_id
		)
	end

	def join_com_programa_diretamente
		%Q(
			JOIN ppa_programas as programa ON projecao.orcador_id = programa.id
		)
	end
end
