require 'httparty'

module ImportacaoTcm
	class LoaDespesa
		@@host = 'https://api.tce.ce.gov.br/index.php/sim/1_0'

		class << self
			def importar codigo_do_municipio, exercicio
				orcamento = Orcamento.find_by(exercicio: exercicio)
				if orcamento.nil?
					ImportacaoTcm::Loa.importar(codigo_do_municipio, exercicio)
					orcamento = Orcamento.find_by(exercicio: exercicio)
				end

				dados_orcamentos_da_despesa = importar_dados_orcamentos_da_despesa(codigo_do_municipio, exercicio)
				criar_orcamentos_da_despesa(dados_orcamentos_da_despesa, orcamento)
			end

			def criar_orcamentos_da_despesa dados_orcamentos_da_despesa, orcamento
				progress_bar = ImportacaoTcm::Loa.barra_de_progresso( titulo: 'DESPESAS', total: dados_orcamentos_da_despesa.size ) unless Rails.env == "test"

				if orcamento.exercicio <= 2014
					grupo_da_fonte_de_recursos = orcamento.grupos_das_fontes_de_recursos.new(modulo_id: orcamento.id, modulo_type: orcamento.class.name, codigo: "0", descricao: "IMPORTADO DO TCM 0")
					grupo_da_fonte_de_recursos.save(validate: false)
				end

				dados_orcamentos_da_despesa.each do |despesa|
					natureza_da_acao = orcamento.naturezas_da_acao.find_by( codigo: despesa['codigo_projeto_atividade'] )
					unidade_orcamentaria = orcamento.orgaos.find_by( codigo: despesa['codigo_orgao']).unidades_orcamentarias.find_by(codigo: despesa['codigo_unidade'].strip )
					unless despesa['codigo_fonte'].blank?
						if orcamento.exercicio > 2018
							fonte_de_recursos = orcamento.fontes_de_recursos.find {|fonte_de_recurso| fonte_de_recurso.codigo_completo[1..9] == despesa['codigo_fonte'].strip }
						else
							fonte_de_recursos = orcamento.fontes_de_recursos.find_by( codigo: despesa['codigo_fonte'].strip )
						end
						if despesa['codigo_fonte'].blank? || fonte_de_recursos.nil?
							grupo_da_fonte_de_recursos = ::Base::GrupoDaFonteDeRecursos.find_by(modulo_id: orcamento.id, modulo_type: orcamento.class.name, codigo: despesa['tipo_fonte'].strip)
							fonte_de_recursos = orcamento.fontes_de_recursos.create(
								codigo: despesa['codigo_fonte'].strip,
								descricao: "IMPORTADO DO TCM #{despesa['codigo_fonte'].strip}",
								grupo_da_fonte_de_recursos_id: grupo_da_fonte_de_recursos.try(:id)
							)
						end
					end

					acao = orcamento.programas_de_governo.find_by(
						codigo: despesa['codigo_programa']
					).acoes.find_by(
						natureza_da_acao_id: natureza_da_acao.id,
						codigo: despesa['numero_projeto_atividade']
					)
					subacao = nil
					subacao = acao.subacoes.find_by(unidade_orcamentaria_id: unidade_orcamentaria.id) if acao.present?

					if subacao.present?
						categoria_economica = Base::CategoriaEconomica.find_by( modulo_id: orcamento.id, modulo_type: orcamento.class.name, codigo: despesa['codigo_elemento_despesa'][0].ljust(8, '0') )
						grupo_de_natureza_da_despesa = Base::GrupoDeNaturezaDaDespesa.find_by( categoria_economica_id: categoria_economica.id, codigo: despesa['codigo_elemento_despesa'][0..1].ljust(8, '0') )
						modalidade_de_aplicacao = Base::ModalidadeDeAplicacao.find_by( grupo_de_natureza_da_despesa_id: grupo_de_natureza_da_despesa.id, codigo: despesa['codigo_elemento_despesa'][0..3].ljust(8, '0') )
						if modalidade_de_aplicacao.blank?
							modalidade_de_aplicacao = criar_modalidade_de_aplicacao( grupo_de_natureza_da_despesa, despesa['codigo_elemento_despesa'][0..3].ljust(8, '0'), "IMPORTADO DO TCM #{despesa['codigo_elemento_despesa'][0..3].ljust(8, '0')}" )
						end

						elemento_de_despesa = Base::ElementoDeDespesa.ativos.find_by( modalidade_de_aplicacao_id: modalidade_de_aplicacao.id, codigo: despesa['codigo_elemento_despesa'] )
						if elemento_de_despesa.blank?
							elemento_de_despesa = criar_elemento_de_despesa( modalidade_de_aplicacao, despesa['codigo_elemento_despesa'], "IMPORTADO DO TCM #{despesa['codigo_elemento_despesa']}" )
						end

						elemento_de_despesa.update_column(:exibir_elemento_de_despesa, true)

						elemento_de_despesa_por_subacao = ::Loa::ElementoDeDespesaPorSubacao.find_by( elemento_de_despesa_id: elemento_de_despesa.id, subacao_id: subacao.id )
						if elemento_de_despesa_por_subacao.blank?
							elemento_de_despesa_por_subacao = criar_elemento_de_despesa_por_subacao( elemento_de_despesa, subacao )
						end

						unless despesa['codigo_fonte'].blank?
							criar_orcamento_da_despesa(elemento_de_despesa_por_subacao, despesa['valor_orcado_categoria_economica'].to_f, fonte_de_recursos)
						end

					else
						p "Subação não encontrada. Pulando para a próxima."
					end
					progress_bar.increment unless Rails.env == "test"
				end
			end

			def importar_dados_orcamentos_da_despesa codigo_do_municipio, exercicio
				response = HTTParty.get("#{@@host}/despesa_elemento_projeto.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00")
				begin
					Hash.from_xml(response.body.encode(Encoding::UTF_8))['rsp']['despesa_elemento_projeto']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_orcamentos_da_despesa codigo_do_municipio, exercicio
				end

			end
		end

		def self.criar_modalidade_de_aplicacao grupo_de_natureza_da_despesa, codigo, descricao
			modalidade_de_aplicacao = ::Base::ModalidadeDeAplicacao.new(
				grupo_de_natureza_da_despesa_id: grupo_de_natureza_da_despesa.id,
				codigo: codigo,
				descricao: descricao
			)
			modalidade_de_aplicacao.save!(validate: false)

			return modalidade_de_aplicacao
		end

		def self.criar_elemento_de_despesa modalidade_de_aplicacao, codigo, descricao
			elemento_de_despesa = ::Base::ElementoDeDespesa.new(
				modalidade_de_aplicacao_id: modalidade_de_aplicacao.id,
				codigo: codigo,
				descricao: descricao
			)
			elemento_de_despesa.save!(validate: false)

			return elemento_de_despesa
		end

		def self.criar_elemento_de_despesa_por_subacao elemento_de_despesa, subacao
			elemento_de_despesa_por_subacao = ::Loa::ElementoDeDespesaPorSubacao.new(
				elemento_de_despesa_id: elemento_de_despesa.id,
				subacao_id: subacao.id,
				status_do_orcamento: 0
			)

			elemento_de_despesa_por_subacao.save!(validate: false)

			return elemento_de_despesa_por_subacao
		end

		def self.criar_orcamento_da_despesa elemento_de_despesa_por_subacao, valor, fonte_de_recursos
			orcamento_da_despesa = ::Loa::OrcamentoDaDespesa.find_by(
				elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id,
				fonte_de_recursos_id: fonte_de_recursos.id
			)

			if orcamento_da_despesa.present?
				inclui_valor_da_fixacao_da_despesa_na_subacao( orcamento_da_despesa.elemento_de_despesa_por_subacao.subacao, valor )
				inclui_valor( orcamento_da_despesa, valor )

			else
				orcamento_da_despesa = ::Loa::OrcamentoDaDespesa.new(
					elemento_de_despesa_por_subacao_id: elemento_de_despesa_por_subacao.id,
					fonte_de_recursos_id: fonte_de_recursos.id,
					valor: valor,
					status_do_orcamento: 0
				)

				inclui_valor_da_fixacao_da_despesa_na_subacao( orcamento_da_despesa.elemento_de_despesa_por_subacao.subacao, valor )
				orcamento_da_despesa.save!
			end
		end

		def self.inclui_valor orcamento_da_despesa, valor
			orcamento_da_despesa.valor += valor
			orcamento_da_despesa.save!
		end

		def self.inclui_valor_da_fixacao_da_despesa_na_subacao subacao, valor
			subacao.fixacao_da_despesa += valor
			subacao.save!(validate: false)
		end

		private_class_method :criar_modalidade_de_aplicacao
		private_class_method :criar_elemento_de_despesa
		private_class_method :criar_elemento_de_despesa_por_subacao
		private_class_method :criar_orcamento_da_despesa
		private_class_method :inclui_valor
		private_class_method :inclui_valor_da_fixacao_da_despesa_na_subacao
	end
end
