require 'httparty'

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

		class << self
			def importar codigo_do_municipio, exercicio
				dados_orcamento = importar_dados_orcamento(codigo_do_municipio, exercicio)
				orcamento = criar_orcamento(dados_orcamento)

				dados_orgaos = importar_dados_orgaos(codigo_do_municipio, exercicio)
				criar_orgaos(dados_orgaos, orcamento)

				dados_unidades_gestoras = importar_dados_unidades_gestoras(codigo_do_municipio, exercicio)
				criar_unidades_gestoras(dados_unidades_gestoras, orcamento)

				dados_gestores_unidades_gestoras = importar_dados_gestores_unidades_gestoras(codigo_do_municipio, exercicio)
				dados_agentes_publicos = importar_dados_agentes_publicos(codigo_do_municipio, exercicio)
				dados_unidades_orcamentarias = importar_dados_unidades_orcamentarias(codigo_do_municipio, exercicio)
				criar_unidades_orcamentarias(dados_unidades_orcamentarias, orcamento, dados_gestores_unidades_gestoras)
				if !dados_agentes_publicos.blank?
					criar_gestores_das_unidades(dados_gestores_unidades_gestoras, orcamento, dados_agentes_publicos)
				end

				dados_programas_de_governo = importar_dados_programas_de_governo(codigo_do_municipio, exercicio)
				criar_programas_de_governo(dados_programas_de_governo, orcamento)

				dados_acoes = importar_dados_acoes_subacoes(codigo_do_municipio, exercicio)
				criar_acoes(dados_acoes, orcamento)

				dados_subacoes = importar_dados_acoes_subacoes(codigo_do_municipio, exercicio)
				criar_subacoes(dados_subacoes, orcamento)
			end

			def barra_de_progresso params
				ProgressBar.create( title: params[:titulo], total: params[:total], :format => "%a %b\u{15E7}%i %p%% %t", :progress_mark  => ' ', :remainder_mark => "\u{FF65}", :starting_at => 0 )
			end

			def criar_orcamento dados_orcamento
				# p "Importando Orçamento #{dados_orcamento['exercicio_orcamento'][0..3]}, lei #{dados_orcamento['nu_lei_orcamento']}." unless Rails.env == "test"
				exercicio = dados_orcamento['exercicio_orcamento'][0..3]
				ppa = Ppa::Ppa.where('exercicio_inicial <= ? and exercicio_final >= ?', exercicio, exercicio).first
				raise "Não existe PPA para o exercício #{exercicio}" if ppa.nil?

				Orcamento.create!(
					ppa_id: ppa.id,
					exercicio: exercicio,
					trabalha_com_subacao: false,
					numero_da_lei: dados_orcamento['nu_lei_orcamento'],
					criar_classificacoes_da_despesa: true,
					percentual_despesa_com_pessoal: 54,
					origem_da_importacao: :api_do_tcm,
					prefeito: ppa.prefeito,
					vice_prefeito: ppa.vice_prefeito
				)
			end

			def criar_orgaos dados_orgaos, orcamento
				progress_bar = barra_de_progresso( titulo: 'ÓRGÃOS', total: dados_orgaos.size ) unless Rails.env == "test"

				dados_orgaos.each do |dados_orgao|
					tipo_de_unidade_administrativa = orcamento.tipos_de_unidades_administrativas.find_by(codigo: dados_orgao['codigo_tipo_unidade'])

					orgao = orcamento.orgaos.new(
					codigo: dados_orgao['codigo_orgao'],
					tipo_de_unidade_administrativa_id: tipo_de_unidade_administrativa.id,
					nome: dados_orgao['nome_orgao'].strip,
					sigla: dados_orgao['codigo_orgao'],
					cnpj: dados_orgao['cgc_orgao'],
					status_do_orcamento: 0
					)
					orgao.save(validate: false)
					progress_bar.increment unless Rails.env == "test"
				end
			end

			def criar_unidades_gestoras dados_unidades_gestoras, orcamento
				progress_bar = barra_de_progresso( titulo: 'UNIDADES GESTORAS', total: dados_unidades_gestoras.size ) unless Rails.env == "test"
				dados_unidades_gestoras.each do |dados_unidade_gestora|
					orcamento.unidades_gestoras.create!(
						codigo: dados_unidade_gestora["codigo_unidade_gestora"].strip,
						nome: dados_unidade_gestora['nome_unidade_gestora'].strip,
						data_de_cadastro: dados_unidade_gestora['data_criacao'][0..9],
						numero_da_lei_de_criacao: dados_unidade_gestora['numero_lei_criacao'],
						status_do_orcamento: 0
					)
					progress_bar.increment unless Rails.env == "test"
				end
			end

			def criar_gestores_das_unidades dados_gestores_unidades_gestoras, orcamento, dados_agentes_publicos
				progress_bar = barra_de_progresso( titulo: 'GESTORES', total: dados_gestores_unidades_gestoras.size ) unless Rails.env == "test"

				dados_agentes_publicos.each do |dados_agente_publico|
					unidade_orcamentaria = orcamento.unidades_orcamentarias.find_by(codigo: dados_agente_publico["codigo_unidade"].try(:strip) )

					pessoa = Base::Pessoa.find_by(cpf: dados_agente_publico["cpf_servidor"].try(:strip))

					if !pessoa.present?
						pessoa = Base::Pessoa.create!(
							nome: dados_agente_publico["nome_servidor"].try(:strip),
							cpf: dados_agente_publico["cpf_servidor"].try(:strip),
							tipo_de_pessoa_id: Base::TipoDePessoa.find_by(codigo: '1').id,
							data_do_cadastro: Date.today,
							cidade_id: Configuracao.last.cidade_id,
							dependentes: dados_agente_publico["numero_dependentes"],
							fornecedor: false
						)
					end

					agente_publico =  Base::AgentePublicoMunicipal.find_by(pessoa_id: pessoa.id, unidade_orcamentaria_id: unidade_orcamentaria.id)

					if !agente_publico.present?
						agente_publico = Base::AgentePublicoMunicipal.create!(
							pessoa_id: pessoa.id,
							unidade_orcamentaria_id: unidade_orcamentaria.id,
							ingresso_sistema_publico_municipal: dados_agente_publico["codigo_ingresso"],
							tipo_relacao_servico_publico: dados_agente_publico["codigo_vinculo"],
							numero_de_posse: dados_agente_publico["numero_expediente_nomeacao"].try(:strip),
							tipo_de_amparo_legal: dados_agente_publico["codigo_amparo_legal"],
							matricula_municipal: dados_agente_publico["numero_matricula"].try(:strip),
							situacao_funcional: dados_agente_publico["situacao_funcional"].to_i,
							regime_juridico: dados_agente_publico["codigo_regime_juridico"],
							regime_previdenciario: dados_agente_publico["codigo_regime_previdencia"],
							codigo_ocupacao: dados_agente_publico["codigo_ocupacao_cbo"].to_i,
							tipo_de_cargo: dados_agente_publico["tipo_cargo"].to_i,
							carga_horaria_semanal: dados_agente_publico["valor_carga_horaria"],
							tipo_de_programa: dados_agente_publico["tipo_programa_social"].to_i,
							codigo_pis_pasep: dados_agente_publico["codigo_programa_social"].try(:strip),
							data_da_posse: (dados_agente_publico["data_posse"].present? ? dados_agente_publico['data_posse'][0..9] : nil),
							data_do_amparo_legal: (dados_agente_publico["data_amparo_legal"].present? ? dados_agente_publico['data_amparo_legal'][0..9] : nil),
							data_da_publicacao_do_amparo_legal: (dados_agente_publico["data_da_publicacao_do_amparo_legal"].present? ? dados_agente_publico['data_da_publicacao_do_amparo_legal'][0..9] : nil)
						)
					end
				end

				dados_gestores_unidades_gestoras.each do |gestor_unidade|
					unidade_gestora = orcamento.unidades_gestoras.find_by(codigo: gestor_unidade["codigo_unidade_gestora"].try(:strip) )
					agente_publico = Base::AgentePublicoMunicipal.joins(:pessoa).where("base_pessoas.cpf = ?", gestor_unidade["cpf_servidor"].try(:strip)).last

					if agente_publico.present? && unidade_gestora.gestores.atual.blank?
						::Loa::Gestor.create!(
							unidade_gestora_id: unidade_gestora.id,
							agente_publico_municipal_id: agente_publico.id,
							inicio_da_gestao: gestor_unidade['data_inicio_gestao'][0..9],
							fim_da_gestao: (gestor_unidade["data_fim_gestao"].present? ? gestor_unidade['data_fim_gestao'][0..9] : nil)
						)

					end

					progress_bar.increment unless Rails.env == "test"
				end
			end

			def criar_unidades_orcamentarias dados_unidades_orcamentarias, orcamento, dados_gestores_unidades_gestoras
				progress_bar = barra_de_progresso( titulo: 'UNIDADES ORCAMENTÁRIAS', total: dados_unidades_orcamentarias.size ) unless Rails.env == "test"

				unless Rails.env == "test"
					puts "Deseja selecionar quais unidades orçamentárias terão suas dependências importadas? (S - Sim, Qualquer Tecla - Não)"
					escolher = importar_dependencias = STDIN.gets.chomp
				end

				dados_unidades_orcamentarias.each do |dados_unidade_orcamentaria|

					tipo_de_administracao = orcamento.tipos_de_administracao.find_by(sigla: dados_unidade_orcamentaria['tipo_administracao_unidade'])
					tipo_de_unidade_administrativa = orcamento.tipos_de_unidades_administrativas.find_by(codigo: dados_unidade_orcamentaria['codigo_tipo_unidade'])
					gestores_unidade_gestora_array = dados_gestores_unidades_gestoras.select {|gestor|
						gestor["codigo_unidade"].try(:strip) == dados_unidade_orcamentaria["codigo_unidade"].strip &&
						gestor["codigo_orgao"] == dados_unidade_orcamentaria["codigo_orgao"]
					}
					codigos = gestores_unidade_gestora_array.map {|ug| ug["codigo_unidade_gestora"]}.uniq
					if codigos.length > 1
						raise "Há mais de uma unidade gestora para uma unidade orçamentária"
					elsif codigos.length == 0
						ug = orcamento.unidades_gestoras.find_by(nome: dados_unidade_orcamentaria['nome_unidade'].strip)
						if ug
							id_unidade_gestora = ug.id
						else
							codigos = orcamento.unidades_gestoras.pluck(:codigo).map { |codigo| codigo.to_i }
							codigo_vazio = ((1..99).to_a - codigos).first
							id_unidade_gestora = orcamento.unidades_gestoras.create!(
							codigo: codigo_vazio.to_s.rjust(2, "0"),
							data_de_cadastro: Time.now.strftime("%Y-%m-%d"),
							numero_da_lei_de_criacao: '0000/00',
							nome: dados_unidade_orcamentaria['nome_unidade'].strip,
							status_do_orcamento: 0
							).id
						end
					else
						id_unidade_gestora = orcamento.unidades_gestoras.find_by(codigo: codigos.first).id
					end

					orgao = ::Loa::Orgao.find_by(
					codigo: dados_unidade_orcamentaria['codigo_orgao'],
					orcamento_id: orcamento.id
					)

					if orgao
						unidade_orcamentaria = ::Loa::UnidadeOrcamentaria.new(
							orgao_id: orgao.id,
							codigo: dados_unidade_orcamentaria['codigo_unidade'].strip,
							nome: dados_unidade_orcamentaria['nome_unidade'].strip,
							sigla: dados_unidade_orcamentaria['codigo_unidade'].strip,
							tipo_de_administracao_id: tipo_de_administracao.id,
							tipo_de_unidade_administrativa_id: tipo_de_unidade_administrativa.id,
							unidade_gestora_id:	 id_unidade_gestora,
							status_do_orcamento: 0,
							skip_validacao: true
						)

						unidade_orcamentaria.save(validate: false)

						unless Rails.env == "test"
							if unidade_orcamentaria && (escolher == 'S' || escolher == 's')
								puts "IMPORTAR AS DEPENDÊNCIAS DO ÓRGÃO #{dados_unidade_orcamentaria['codigo_orgao']}, UNIDADE #{dados_unidade_orcamentaria['codigo_unidade']} - #{dados_unidade_orcamentaria['nome_unidade']} (N - NÃO, Qualquer Tecla - SIM): "
								importar_dependencias = STDIN.gets.chomp
								if importar_dependencias == 'N' || importar_dependencias == 'n'
									unidade_orcamentaria.importar_dependencias = false
								unidade_orcamentaria.save(validate: false)
								end
							end
						end
					end

					progress_bar.increment unless Rails.env == "test"
				end

				# # temporario
				# unless Rails.env == "test"
				# 	orgao = ::Loa::Orgao.find_by(codigo: '01')
				# 	unidade_orcamentaria = ::Loa::UnidadeOrcamentaria.find_by(orgao_id: orgao.id, codigo: '10')
				# 	unidade_orcamentaria.update(importar_dependencias: false)
				# 	orgao = ::Loa::Orgao.find_by(codigo: '05')
				# 	unidade_orcamentaria = ::Loa::UnidadeOrcamentaria.find_by(orgao_id: orgao.id, codigo: '20')
				# 	unidade_orcamentaria.update(importar_dependencias: false)
				# 	orgao = ::Loa::Orgao.find_by(codigo: '03')
				# 	unidade_orcamentaria = ::Loa::UnidadeOrcamentaria.find_by(orgao_id: orgao.id, codigo: '04')
				# 	unidade_orcamentaria.update(importar_dependencias: false)
				# end
			end

			def criar_programas_de_governo dados_programas_de_governo, orcamento
				progress_bar = barra_de_progresso( titulo: 'PROGRAMAS', total: dados_programas_de_governo.size ) unless Rails.env == "test"
				dados_programas_de_governo.each do |dados_do_programa|
					programa = orcamento.programas_de_governo.new(
						codigo: dados_do_programa['codigo_programa'],
						nome: dados_do_programa['nome_programa'].strip,
						status_do_orcamento: 0
					)
					programa.save(validate: false)
					progress_bar.increment unless Rails.env == "test"
				end
			end

			def criar_acoes dados_acoes, orcamento
				progress_bar = barra_de_progresso( titulo: 'AÇÕES', total: dados_acoes.size ) unless Rails.env == "test"
				dados_acoes.each do |dados_acao|
					natureza_da_acao = orcamento.naturezas_da_acao.find_by(codigo: dados_acao['codigo_projeto_atividade'])

					orcamento.programas_de_governo.find_by(
						codigo: dados_acao['codigo_programa']
					).acoes.new(
						codigo: dados_acao['numero_projeto_atividade'],
						nome: dados_acao['nome_projeto_atividade'].strip,
						descricao: dados_acao['descricao_projeto_atividade'].strip,
						natureza_da_acao_id: natureza_da_acao.id,
						status_do_orcamento: 0
					).save(validate: false)
					progress_bar.increment unless Rails.env == "test"
				end
			end

			def criar_subacoes dados_subacoes, orcamento
				progress_bar = barra_de_progresso( titulo: 'SUBAÇÕES', total: dados_subacoes.size ) unless Rails.env == "test"
				subacoes = []
				dados_subacoes.each do |dados_subacao|
					natureza_da_acao = orcamento.naturezas_da_acao.find_by(codigo: dados_subacao['codigo_projeto_atividade'])
					unidade_orcamentaria = orcamento.orgaos.find_by(codigo: dados_subacao['codigo_orgao']).unidades_orcamentarias.find_by(codigo: dados_subacao['codigo_unidade'].strip)
					funcao = orcamento.funcoes.find_by(codigo: dados_subacao['codigo_funcao'])
					subfuncao = orcamento.subfuncoes.find_by(codigo: dados_subacao['codigo_subfuncao'])
					tipo_de_orcamento = orcamento.tipos_de_orcamento.find_by(codigo: dados_subacao['codigo_tipo_orcamento'])

					subacao = orcamento.programas_de_governo.find_by(
						codigo: dados_subacao['codigo_programa']
					).acoes.find_by(
						natureza_da_acao_id: natureza_da_acao.id,
						codigo: dados_subacao['numero_projeto_atividade']
					).subacoes.new(
						codigo: dados_subacao['numero_subprojeto_atividade'],
						unidade_orcamentaria_id: unidade_orcamentaria.id,
						funcao_id: funcao.id,
						subfuncao_id: subfuncao.id,
						tipo_de_orcamento_id: tipo_de_orcamento.id,
						status_do_orcamento: 0
					)
					unless subacao.save
						if subacao.errors[:codigo].any?
							subacoes << subacao
						end
					end
					progress_bar.increment unless Rails.env == "test"
				end

				subacoes.each do |subacao|
					subacao.codigo = subacao.gerar_sugestao_codigo( :codigo, 4, { acao_id: subacao.acao.id } )
					subacao.save
				end
			end

			# Métodos que realizam a importação dos dados da API do TCM
			def importar_dados_orcamento codigo_do_municipio, exercicio
				response = HTTParty.get( "#{@@host}/dados_orcamentos.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					dados_orcamento = Hash.from_xml(response.body.force_encoding("UTF-8"))['rsp']['dados_orcamentos']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_orcamento codigo_do_municipio, exercicio
				end
			end

			def importar_dados_orgaos codigo_do_municipio, exercicio
				response = HTTParty.get( "#{@@host}/orgaos.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					dados_orgaos = Hash.from_xml(response.body.force_encoding("UTF-8"))['rsp']['orgaos']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_orgaos codigo_do_municipio, exercicio
				end
			end

			def importar_dados_unidades_gestoras codigo_do_municipio, exercicio
				response = HTTParty.get( "#{@@host}/unidades_gestoras.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					dados_unidades_gestoras = Hash.from_xml(response.body.force_encoding("UTF-8"))['rsp']['unidades_gestoras']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_unidades_gestoras codigo_do_municipio, exercicio
				end
			end

			def importar_dados_unidades_orcamentarias codigo_do_municipio, exercicio
				# XML
				#response = HTTParty.get( "#{@@host}/unidades_orcamentarias.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )

				# JSON
				response = HTTParty.get( "#{@@host}/unidades_orcamentarias.json?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					#dados_unidades_orcamentarias = Hash.from_xml(response.body.force_encoding("UTF-8"))['rsp']['unidades_orcamentarias']
					dados_unidades_orcamentarias = JSON.parse(response.body.force_encoding("UTF-8"))['rsp']['_content']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_unidades_orcamentarias codigo_do_municipio, exercicio
				end
			end

			def importar_dados_gestores_unidades_gestoras codigo_do_municipio, exercicio
				response = HTTParty.get( "#{@@host}/gestores_unidades_gestoras.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					response_body = response.body.encode('utf-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
					dados_gestores_unidades_gestoras = Hash.from_xml(response_body.force_encoding("UTF-8"))['rsp']['gestores_unidades_gestoras']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_gestores_unidades_gestoras codigo_do_municipio, exercicio
				end
			end

			def importar_dados_agentes_publicos codigo_do_municipio, exercicio
				# XML
				#response = HTTParty.get( "#{@@host}/agentes_publicos.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				#dados_agentes_publicos = Hash.from_xml(response.body.force_encoding("UTF-8"))['rsp']['agentes_publicos']

				# JSON
				response = HTTParty.get( "#{@@host}/agentes_publicos.json?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					response_body = response.body.encode('utf-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
					dados_agentes_publicos = JSON.parse(response_body.force_encoding("UTF-8"))['rsp']['_content']
				rescue
					puts "Página não encontrada para Agentes públicos, tentando novamente..."
					@@count_agentes_publicos += 1
					sleep 5
					if @@count_agentes_publicos <= 3
						importar_dados_agentes_publicos codigo_do_municipio, exercicio
					end
				end
			end

			def importar_dados_programas_de_governo codigo_do_municipio, exercicio
				response = HTTParty.get( "#{@@host}/programas.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					dados_programas_de_governo = Hash.from_xml(response.body.force_encoding("UTF-8"))['rsp']['programas']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_programas_de_governo codigo_do_municipio, exercicio
				end
			end

			def importar_dados_acoes_subacoes codigo_do_municipio, exercicio
				response = HTTParty.get( "#{@@host}/despesa_projeto_atividade.xml?codigo_municipio=#{codigo_do_municipio}&exercicio_orcamento=#{exercicio}00" )
				begin
					response_body = response.body.encode('utf-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
					dados_acoes = Hash.from_xml(response_body.force_encoding("UTF-8"))['rsp']['despesa_projeto_atividade']
				rescue
					puts "Página não encontrada, tentando novamente..."
					sleep 5
					importar_dados_acoes_subacoes codigo_do_municipio, exercicio
				end
			end
		end
	end
end
