require 'active_support/concern'

module ValidaOrcamentoConcern extend ActiveSupport::Concern

	def validar_valores_de_receita_e_despesa
		receita_fiscal = valor_total_previsto_da_receita(Base::TipoDeOrcamento.find_by(codigo: 'F', modulo: self))
		receita_seguridade_social = valor_total_previsto_da_receita(Base::TipoDeOrcamento.find_by(codigo: 'S', modulo: self))
		despesa_fiscal = valor_total_fixado_da_despesa(Base::TipoDeOrcamento.find_by(codigo: 'F', modulo: self))
		despesa_seguridade_social = valor_total_fixado_da_despesa(Base::TipoDeOrcamento.find_by(codigo: 'S', modulo: self))

		receita = receita_fiscal + receita_seguridade_social
		despesa = despesa_fiscal + despesa_seguridade_social

		lista = Array.new
		lista << "Nenhuma RECEITA informada até o momento." if receita <= 0
		lista << "Nenhuma RECEITA DE SEGURIDADE SOCIAL informada até o momento." if receita_seguridade_social <= 0 && receita > 0
		lista << "Nenhuma RECEITA FISCAL informada até o momento." if receita_fiscal <= 0 && receita > 0
		lista << "Nenhuma DESPESA informada até o momento." if despesa <= 0
		lista << "Nenhuma DESPESA DE SEGURIDADE SOCIAL informada até o momento." if despesa_seguridade_social <= 0 && despesa > 0
		lista << "Nenhuma DESPESA FISCAL informada até o momento." if despesa_fiscal <= 0 && despesa > 0
		lista << "O total das RECEITAS do orçamento é <b>#{receita.try(:contabil)}</b> enquanto o total da DESPESA é <b>#{despesa.try(:contabil)}</b>. Diferença: #{(receita - despesa).try(:contabil)}" if receita != despesa
		#lista << "O total das RECEITAS DE SEGURIDADE SOCIAL é de <b>#{receita_seguridade_social.try(:contabil)}</b> enquanto o total da despesa é de <b>#{despesa_seguridade_social.try(:contabil)}</b>" if receita_seguridade_social != despesa_seguridade_social
		#lista << "O total das RECEITAS FISCAIS é de <b>#{receita_fiscal.try(:contabil)}</b> enquanto o total da DESPESA é de <b>#{despesa_fiscal.try(:contabil)}</b>. Diferença: #{(receita_fiscal - despesa_fiscal).try(:contabil)}" if receita_fiscal != despesa_fiscal
		return lista
	end

	def informativo_dos_valores_totais
		receita_fiscal = valor_total_previsto_da_receita(Base::TipoDeOrcamento.find_by(codigo: 'F', modulo: self))
		receita_seguridade_social = valor_total_previsto_da_receita(Base::TipoDeOrcamento.find_by(codigo: 'S', modulo: self))
		despesa_fiscal = valor_total_fixado_da_despesa(Base::TipoDeOrcamento.find_by(codigo: 'F', modulo: self))
		despesa_seguridade_social = valor_total_fixado_da_despesa(Base::TipoDeOrcamento.find_by(codigo: 'S', modulo: self))

		valor_a_transferir_seguridade_social = despesa_seguridade_social.to_f - receita_seguridade_social.to_f

		lista = Array.new
		lista << "O valor da RECEITA DE SEGURIDADE SOCIAL informada até o momento é de #{receita_seguridade_social.try(:contabil)}" if receita_seguridade_social.to_f > 0
		lista << "O valor da DESPESA DE SEGURIDADE SOCIAL informada até o momento é de #{despesa_seguridade_social.try(:contabil)}" if despesa_seguridade_social.to_f > 0
		lista << "O valor da RECEITA FISCAL informada até o momento é de #{receita_fiscal.try(:contabil)}" if receita_fiscal.to_f > 0
		lista << "O valor da DESPESA FISCAL informada até o momento é de #{despesa_fiscal.try(:contabil)}" if despesa_fiscal.to_f > 0
		lista << "O valor da despesa de seguridade social financiado pela receita fiscal é de #{valor_a_transferir_seguridade_social.try(:contabil)}" if valor_a_transferir_seguridade_social > 0
		return lista
	end

	def lista_orgao_sem_unidades_orcamentarias root_url
		self.orgaos.map{|orgao|
			orgao.unidades_orcamentarias.any? ? nil : " Orgão <a id='url' href=\"#{root_url + 'loa/orgaos/' + orgao.id.to_s}\">#{orgao.nome.try(:upcase)}</a> não possui Unidade Orçamentária."
		}.compact
	end

	def programas_sem_acao_cadastrada root_url
		self.programas_de_governo.map {|programa|
			programa.acoes.any? ? nil : " Programa de Governo <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + programa.id.to_s}\">#{programa.nome.try(:upcase)}</a> não possui ação cadastrada."
		}.compact
	end

	def acoes_sem_subacao_cadastrada root_url
		acoes = []
		self.programas_de_governo.map {|programa_de_governo|
			programa_de_governo.acoes.map {|acao|
				acoes << "Ação <a id='url' href=\"#{root_url + 'loa/acoes/' + acao.id.to_s}\">#{acao.nome.try(:upcase)}</a>  do programa <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + acao.programa_de_governo.id.to_s}\">#{acao.programa_de_governo.nome.try(:upcase)}</a> não possui Subação." unless acao.subacoes.any?
			}
		}
		return acoes
	end

	def lista_orcamento_de_despesa_sem_iduso root_url
		if trabalhar_com_iduso
			subacoes = []
			self.programas_de_governo.map {|programa_de_governo|
				programa_de_governo.acoes.map {|acao|
					acao.subacoes.map {|subacao|
						subacoes << "Subação <a id='url' href=\"#{root_url + 'loa/subacoes/' + subacao.id.to_s}\">#{subacao.codigo}</a> da Ação <a id='url' href=\"#{root_url + 'loa/acoes/' + subacao.acao.id.to_s}\">#{subacao.acao.nome.try(:upcase)}</a> do programa <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + subacao.acao.programa_de_governo.id.to_s}\">#{subacao.acao.programa_de_governo.nome.try(:upcase)}</a> possui orçamentos da despesa sem o tipo de iduso informado." if subacao.orcamentos_da_despesa.where("iduso is null or iduso = 0").count > 0
					}
				}
			}
			return subacoes
		end
	end

	def receita_intraorcamentaria_igual_modalidade_de_aplicacao_despesa root_url
		total_despesa = 0
		total_receita = 0
		self.elementos_de_despesa.map{|elemento|
			if elemento.modalidade_de_aplicacao.pertence_a_91?
				elemento.orcamentos_da_despesa.map{|despesa|
					total_despesa += despesa.valor
				}
			end
		}

		self.naturezas_da_receita.map{|receita|
			if receita.intra_orcamentaria?
				receita.orcamentos_da_receita.map{|orcamento_da_receita|
					total_receita += orcamento_da_receita.valor
				}
			end
		}
		total_despesa.to_f == total_receita.to_f ? [] : ["O valor total das Receitas Intra-Orçamentárias é de de <b>#{total_receita.real_contabil}</b> enquanto o total da despesa para Modalidades de Aplicações é de <b>#{total_despesa.real_contabil}</b>"]
	end

	def subacoes_sem_orcamento_de_despesa_cadastrado root_url
		subacoes = []
		self.programas_de_governo.map {|programa_de_governo|
			programa_de_governo.acoes.map {|acao|
				acao.subacoes.map {|subacao|
					subacoes << "Subação <a id='url' href=\"#{root_url + 'loa/subacoes/' + subacao.id.to_s}\">#{subacao.codigo}</a> da Ação <a id='url' href=\"#{root_url + 'loa/acoes/' + subacao.acao.id.to_s}\">#{subacao.acao.nome.try(:upcase)}</a> do programa <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + subacao.acao.programa_de_governo.id.to_s}\">#{subacao.acao.programa_de_governo.nome.try(:upcase)}</a> não possui Orçamento da Despesa informado."unless subacao.orcamentos_da_despesa.any?
				}
			}
		}
		return subacoes
	end

	def lista_de_programas_do_governo_nao_validados root_url
		self.programas_de_governo.map {|programa|
			programa.validate ? nil : "Programa de Governo <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + programa.id.to_s}\">#{programa.nome.try(:upcase)}</a> possui campos obrigatórios não preenchidos."
		}.compact
	end

	def lista_acoes_nao_validados root_url
		acoes = []
		self.programas_de_governo.map {|programa_de_governo|
			programa_de_governo.acoes.map {|acao|
				acoes << "Ação <a id='url' href=\"#{root_url + 'loa/acoes/' + acao.id.to_s}\">#{acao.nome.try(:upcase)}</a> do programa <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + acao.programa_de_governo.id.to_s}\">#{acao.programa_de_governo.nome.try(:upcase)}</a> possui campos obrigatórios não preenchidos." unless acao.valid?
			}
		}
		return acoes
	end

	def lista_subacoes_nao_validados root_url
		subacoes = []
		self.programas_de_governo.map {|programa_de_governo|
			programa_de_governo.acoes.map {|acao|
				acao.subacoes.map {|subacao|
					subacoes << "Subação <a id='url' href=\"#{root_url + 'loa/subacoes/' + subacao.id.to_s}\">#{subacao.codigo}</a> da Ação <a id='url' href=\"#{root_url + 'loa/acoes/' + acao.id.to_s}\">#{acao.nome.try(:upcase)}</a> do programa <a id='url' href=\"#{root_url + 'loa/programas_de_governo/' + acao.programa_de_governo.id.to_s}\">#{acao.programa_de_governo.nome.try(:upcase)}</a> possui campos obrigatórios não preenchidos." unless subacao.valid?
				}
			}
		}
		return subacoes
	end

	def lista_fontes_de_recurso_com_diferenca root_url
		fontes_de_recursos = []
		self.fontes_de_recursos.map {|fonte_de_recurso|
			fontes_de_recursos << "Fonte de Recursos <a id='url' href=\"#{root_url + 'fontes_de_recursos/' + fonte_de_recurso.id.to_s}\">#{fonte_de_recurso.codigo_e_descricao.try(:upcase)}</a> possuí diferença entre a receita e a despesa de <b>#{fonte_de_recurso.diferenca_entre_receita_e_despesa.try(:contabil)}</b>. Receita: #{fonte_de_recurso.total_da_receita.try(:contabil)} | Despesa: #{fonte_de_recurso.total_da_despesa.try(:contabil)}" unless fonte_de_recurso.diferenca_entre_receita_e_despesa == 0
		}
		return fontes_de_recursos
	end

	def lista_unidades_orcamentarias_por_fontes_de_recurso_com_diferenca  root_url
		unidades_orcamentarias = []
		self.unidades_orcamentarias.each do |unidade_orcamentaria|
			fontes_de_recursos = unidade_orcamentaria.fontes_de_recursos.to_a | unidade_orcamentaria.fontes_de_recursos_da_receita.to_a
			fontes_de_recursos.each do |fonte_de_recurso|
				diferenca = unidade_orcamentaria.diferenca_entre_receita_e_despesa_por_fonte_de_recurso(fonte_de_recurso.id)
				receita = unidade_orcamentaria.total_da_receita_por_fonte_de_recurso(fonte_de_recurso.id)
				despesa = unidade_orcamentaria.total_da_despesa_por_fonte_de_recurso(fonte_de_recurso.id)
				unidades_orcamentarias <<
				"Unidade Orçamentária <a id='url' href=\"#{root_url + 'loa/unidades_orcamentarias/'+ unidade_orcamentaria.id.to_s}\">#{unidade_orcamentaria.codigo_e_nome.try(:upcase)}</a>
				 na fonte de recurso <a id='url' href=\"#{root_url + 'fontes_de_recursos/' + fonte_de_recurso.id.to_s}\">#{fonte_de_recurso.codigo_e_descricao.try(:upcase)}</a> possuí diferença entre a receita e a despesa de <b>#{diferenca.real_contabil}</b>| receita: <b>#{receita.real_contabil}</b> |despesa: <b>#{despesa.real_contabil}</b>" unless diferenca == 0.0
			end
		end

		return unidades_orcamentarias
	end

	def lista_diferenca_da_reserva_de_contigencia root_url
		if self.percentual_da_reserva_de_contingencia.to_f != 0.0
			elemento_de_despesa = self.categorias_economicas.find_by(codigo: '90000000').elementos_de_despesa.first
			valor_total_reserva_de_contingencia = elemento_de_despesa.orcamentos_da_despesa.joins(elemento_de_despesa_por_subacao: [subacao: [:funcao, :subfuncao]]).where(base_funcoes: {codigo: '99'}, base_subfuncoes: {codigo: '999'}).sum(:valor)
			valor_total_reserva_de_contingencia.to_f <= self.valor_da_reserva_de_contigencia_projetado.to_f ? [] :
			["O valor da Reserva de Contingência fixado na LOA (<b>#{valor_total_reserva_de_contingencia.to_f.real_contabil}</b>) está maior do que o limite máximo estabelecido na LDO (<b>#{self.valor_da_reserva_de_contigencia_projetado.to_f.real_contabil}</b>).A diferença é de <b>#{(self.valor_da_reserva_de_contigencia_projetado.to_f - valor_total_reserva_de_contingencia.to_f).real_contabil}</b> "]
		else
			["Não foi informado um valor percentual de contigência para este orçamento."]
		end
	end

	def valida_percentual_gasto_com_magisterio
		["O gasto com MAGISTÉRIO é de #{percentual_gasto_com_magisterio}% (#{valor_total_gasto_com_magisterio.try(:contabil)}), abaixo do valor mínimo de 60,00% (#{percentual_ideal_para_gasto_com_magisterio.try(:contabil)})."] if percentual_gasto_com_magisterio < 60
	end

	def informativo_percentual_gasto_com_magisterio
		["O gasto com MAGISTÉRIO é de #{percentual_gasto_com_magisterio}% (#{valor_total_gasto_com_magisterio.try(:contabil)}) de um total de #{valor_total_das_receitas_do_fundeb.try(:contabil)} em receitas do FUNDEB."] if percentual_gasto_com_magisterio >= 60
	end

	def valida_percentual_da_receita_de_educacao
		fonte_educacao = self.fontes_de_recursos.find_by(codigo: '02')
		if fonte_educacao != nil
			if fonte_educacao.percentual_minimo_de_destinacao.to_f > 0
				["Receitas lançadas na FONTE 02 - MDE está em #{percentual_das_receitas_por_fonte_de_recurso('02').try(:contabil)}% (#{valor_total_das_receitas_por_fonte_de_recurso('02').try(:contabil)}); Sendo o mínimo de #{fonte_educacao.percentual_minimo_de_destinacao.to_f}% (#{percentual_ideal_das_receitas_que_contem_a_fonte_de_recurso('02', fonte_educacao.percentual_minimo_de_destinacao.to_f).try(:contabil)}) "] if percentual_aplicado_em_educacao.to_f < fonte_educacao.percentual_minimo_de_destinacao.to_f
			else
				["Não foi informado um percentual mínimo na fonte de recurso 02 para que seja possível calcular se o mesmo foi aplicado."]
			end
		end
	end

	def informativo_percentual_da_receita_de_educacao
		["O percentual lançado para a fonte de recurso 02 - EDUCAÇÃO é de #{percentual_das_receitas_por_fonte_de_recurso('02').try(:contabil)}% (#{valor_total_das_receitas_por_fonte_de_recurso('02').try(:contabil)}) do total de receitas (#{valor_total_das_receitas_que_contem_a_fonte_de_recurso('02').try(:contabil)}) que contem essa mesma fonte de recurso."] if percentual_das_receitas_por_fonte_de_recurso('02').to_f >= 25
	end

	def valida_percentual_da_receita_da_saude
		fonte_saude = self.fontes_de_recursos.find_by(codigo: '03')
		if fonte_saude != nil
			if fonte_saude.percentual_minimo_de_destinacao.to_f > 0
				["Receitas lançadas na FONTE 03 - SAÚDE está em #{percentual_das_receitas_por_fonte_de_recurso('03').try(:contabil)}% (#{valor_total_das_receitas_por_fonte_de_recurso('03').try(:contabil)}); Sendo o mínimo de #{fonte_saude.percentual_minimo_de_destinacao.to_f}% (#{percentual_ideal_das_receitas_que_contem_a_fonte_de_recurso('03', fonte_saude.percentual_minimo_de_destinacao.to_f).try(:contabil)}) "] if percentual_das_receitas_por_fonte_de_recurso('03').to_f < fonte_saude.percentual_minimo_de_destinacao.to_f
			else
				["Não foi informado um percentual mínimo na fonte de recurso 03 para que seja possível calcular se o mesmo foi aplicado."]
			end
		end
	end

	def valida_se_existe_modalidade_de_aplicacao_91
		erros = []
		if elementos_de_despesa.joins(:orcamentos_da_despesa).where("substring(base_elementos_de_despesa.codigo from 3 for 2) = '91'").blank? && self.unidades_orcamentarias.where(rpps:true).count > 0
			erros.push "É obrigatório ter despesa associada com a modalidade de aplicação 91 cadastrada no sistema"
		end

		return erros
	end

	def valida_unidade_orcamentaria_saae
		erros = []
		unidades_orcamentarias.where(saae:true).each do |unidade_orcamentaria|
			unless unidade_orcamentaria.subacoes.joins(:elementos_de_despesa).where("substring(base_elementos_de_despesa.codigo from 3 for 4) = '9139'").present?
				erros.push "Unidade Orçamentária #{unidade_orcamentaria.codigo} deve ter elemento de despesa no formato X.X.91.39.XX."
			end
		end

		return erros
	end

	def valida_unidade_administrativa_superavitaria
		erros = []
		unidades_orcamentarias.where(situacao_orcamentaria: 0).each do |unidade_orcamentaria|
			unless unidade_orcamentaria.subacoes.joins(:elementos_de_despesa).where("substring(base_elementos_de_despesa.codigo from 1 for 1) = '9'").present?
				erros.push "Unidade Orçamentária #{unidade_orcamentaria.codigo} deve ter uma reserva de contigência associada"
			end
		end

		return erros
	end

	def valida_receita_intra_do_rpps
		erros = []
		total_despesa = 0
		elementos_de_despesa.where("substring(base_elementos_de_despesa.codigo from 3 for 4) IN ('9113', '9121', '9122', '9171', '9173', '9192')").each do |elemento_de_despesa|
			total_despesa += elemento_de_despesa.valor_total_fixado_da_despesa
		end

		total_receita = 0
		Loa::OrcamentoDaReceita.joins(unidade_orcamentaria_por_natureza_da_receita: [:unidade_orcamentaria, :natureza_da_receita]).where(loa_unidades_orcamentarias: {rpps: true}, base_naturezas_da_receita: {modulo_id: id, modulo_type: 'Orcamento'}).where("substring(base_naturezas_da_receita.codigo from 3 for 1) IN ('7', '8')").each do |orcamento_da_receita|
			total_receita += orcamento_da_receita.valor
		end

		if total_despesa != total_receita
			erros.push "Receita de RPPS Intra deve ser igual as despesas com modalidades de aplicação 9113, 9121, 9122, 9171, 9173. Total da Receita: #{total_receita.try(:contabil)}. Total da Despesa: #{total_despesa.try(:contabil)}"
		end
	end

	def informativo_percentual_da_receita_da_saude
		["O percentual lançado para a fonte de recurso 03 - SAÚDE é de #{percentual_das_receitas_por_fonte_de_recurso('03').try(:contabil)}% (#{valor_total_das_receitas_por_fonte_de_recurso('03').try(:contabil)}) do total de receitas (#{valor_total_das_receitas_que_contem_a_fonte_de_recurso('03').try(:contabil)}) que contem essa mesma fonte de recurso."] if percentual_das_receitas_por_fonte_de_recurso('03').to_f >= 15
	end

	def informativo_percentual_aplicado_em_saude
		["O valor aplicado nas ações públicas de saúde é de #{valor_total_aplicado_em_saude.try(:contabil)} e corresponde a #{percentual_aplicado_em_saude.try(:contabil)}% da receita."] if percentual_aplicado_em_saude >= 0
	end

	def informativo_percentual_aplicado_em_educacao
		["O valor aplicado na manutenção e desenvolvimento do ensino é de #{valor_total_aplicado_em_educacao.try(:contabil)} e corresponde a #{percentual_aplicado_em_educacao.try(:contabil)}% da receita."] if percentual_aplicado_em_educacao >= 0
	end

	def valida_percentual_aplicado_em_saude
		["O valor aplicado nas ações públicas de saúde está negativo em #{valor_total_aplicado_em_saude.try(:contabil)} e corresponde a #{percentual_aplicado_em_saude.try(:contabil)}% da receita."] if percentual_aplicado_em_saude < 0
	end

	def valida_percentual_aplicado_em_educacao
		["O valor aplicado na manutenção e desenvolvimento do ensino está negativo em #{valor_total_aplicado_em_educacao.try(:contabil)} e corresponde a #{percentual_aplicado_em_educacao.try(:contabil)}% da receita."] if percentual_aplicado_em_educacao < 0
	end
end
