class Configuracao < ApplicationRecord
	has_paper_trail
	include TradutorConcern

	belongs_to :empresa_desenvolvedora, class_name: "Base::Pessoa", foreign_key: "empresa_desenvolvedora_id"

	attr_default :permite_lancamentos_no_sabado, true
	attr_default :permite_lancamentos_no_domingo, false
	attr_default :permite_lancamentos_em_feriados, false
	attr_default :permite_saldo_das_contas_do_plano_de_contas_vire, true #TODO: Isso deve ser mudado para false assim que a funcionalidade de crédito inicial for finalizada
	attr_default :tipo, :prefeitura
	attr_default :tipo_de_acesso, :nao_monitorado
	attr_default :implantacao, false
	attr_default :gerar_lote_somente_com_pagamento_completo, false

	# PARAMETRIZAÇÕES
	attr_default :comite_programacao_financeira, false
	attr_default :envia_projeto_para_controladoria, false
	attr_default :permite_envio_de_email, false
	attr_default :obriga_dotacao_para_registro_com_preco, false
	attr_default :envia_empenho_para_controladoria, false
	attr_default :envia_empenho_para_copfin, false
	attr_default :francionamento_de_dispensa_por_subelemento, true
	attr_default :francionamento_de_dispensa_por_cnpj, false
	attr_default :francionamento_de_dispensa_por_unidade_gestora, false
	attr_default :envia_parecer_inicial, false
	attr_default :envia_parecer_final, false
	attr_default :envia_documentos_para_controladoria, false
	attr_default :envia_documentos_para_copfin, false
	attr_default :obriga_termo_de_referencia, true
	attr_default :obriga_documento_de_autorizacao, true
	attr_default :obriga_termo_de_autuacao, true
	attr_default :obriga_despacho, true
	attr_default :obriga_minuta_de_contrato, true
	attr_default :obriga_minuta_de_ata_de_registro_de_preco, true
	attr_default :valida_saldo_da_dotacao_no_pb, false
	attr_default :valida_saldo_da_dotacao_no_empenho, false
	attr_default :exibe_assinatura_copfin, true
	attr_default :exibe_assinatura_controladoria, true
	attr_default :comprometimento_de_dotacoes, false
	attr_default :envia_empenho_para_contabilidade, false
	attr_default :envia_liquidacao_para_contabilidade, false
	attr_default :envia_email_pagamento_confirmado, false
	attr_default :exibe_assinatura_ordenador, false
	attr_default :obriga_medicao_da_obra_na_liquidacao_adm, true
	attr_default :enviar_relatorio_de_medicao, false
	attr_default :envia_liquidacao_para_controladoria, false
	attr_default :envia_pagamento_para_controladoria, false
	attr_default :envia_documento_para_controladoria, false
	attr_default :permite_uso_da_bolsa_de_materiais, false
	attr_default :prazo_da_entrada_automatica_na_bolsa_de_materiais, 120
	attr_default :prazo_da_analise_da_entrada_na_bolsa_de_materiais, 15
	attr_default :numeracao_do_tombamento, 'AAAA99999999999'
	attr_default :exibe_identificacao_da_empresa_desenvolvedora, false
	attr_default :usar_centro_de_custos_na_localizacao_do_bem, false
	attr_default :iniciar_fluxo_pelo_patrimonio, false
	attr_default :utiliza_saldo_de_implantacao, false
	attr_default :prazo_sem_movimentacao_de_material, 15
	attr_default :obriga_competencia_em_despesas_extra_orcamentarias, false
	attr_default :utiliza_almoxarifado, true
	attr_default :permite_encerramento_anual_do_estoque, false
	attr_default :obriga_preenchimento_de_nf, true
	attr_default :faz_envio_do_sim, false
	attr_default :obriga_inscricao_do_fornecedor_na_liquidacao, false

	attr_default :exibir_data_no_documento_solicitacao_empenho, false
	attr_default :exibir_data_no_documento_solicitacao_liquidacao , false

	belongs_to :cidade, class_name: "Base::Cidade"
	belongs_to :estado, class_name: "Base::Estado"

	has_one :customizacao
	accepts_nested_attributes_for :customizacao

	has_many :configuracoes_sim, class_name: "ConfiguracaoSim"
	accepts_nested_attributes_for :configuracoes_sim

	has_many :parametrizacao_modulos, class_name: "ParametrizacaoModulo"
	accepts_nested_attributes_for :parametrizacao_modulos

	has_many :parametrizacoes_portal_da_transparencia, class_name: "ParametrizacaoPortalDaTransparencia"
	accepts_nested_attributes_for :parametrizacoes_portal_da_transparencia
	validates_associated :parametrizacoes_portal_da_transparencia

	validates_format_of :mascara_numero_do_processo, :with => /\A[DXOSMA\W]+\Z/, allow_nil: true

	has_attached_file :brasao, styles: { large: "500x500>", medium: "300x300>", thumb: "100x100>" }, :default_url => "/speedgov.png"
	validates_attachment_content_type :brasao, content_type: /\Aimage\/.*\Z/
	validates_attachment_size :brasao, in: 0..2.megabytes
	validates_attachment_file_name :brasao, matches: [/png\z/, /jpe?g\z/], message: 'Apenas PNG, JPG e JPEG'

	validate :apenas_uma_configuracao_cadastrada, on: :create
	validate :valida_formatacao_do_email_principal, if: Proc.new{ autorizacao_de_pagamento_via_email? && email_principal_da_autorizacao.present? }
	validate :valida_formatacao_do_email_secundario, if: Proc.new{ autorizacao_de_pagamento_via_email? && email_secundario_da_autorizacao.present? }

	validates_length_of :codigo_do_municipio_no_tcm, is: 3, if: Proc.new{|configuracao| configuracao.codigo_do_municipio_no_tcm.present?}
	validates_length_of :numeracao_do_tombamento, maximum: 20

	validates_presence_of :estado_id, :cidade_id, if: :persisted?

	validates_presence_of :email_principal_da_autorizacao, on: :update, if: Proc.new { autorizacao_de_pagamento_via_email? }

	validates_presence_of :data_vencimento_acesso, if: :monitorado?
	validates_absence_of :data_vencimento_acesso, if: :nao_monitorado?

	after_save :alterar_status_conforme_parametrizacao, on: :update, if: Proc.new { !self.valida_saldo_da_dotacao_no_empenho?}

	enum tipo: {
		prefeitura: 0,
		camara_municipal: 1
	}

	enum tipo_de_acesso: {
		nao_monitorado: 0,
		monitorado: 1
	}
	
	enum bloqueio_geral: {
		nao_bloqueado: 0,
		bloqueado_para_o_sim: 1,
		bloqueado_nao_especificado: 99
	}

	def sistema_bloqueado?
		self.bloqueio_geral_before_type_cast.to_i > 0
	end

	def alterar_status_conforme_parametrizacao
		Contabilidade::Empenho.aguardando_alteracao_do_orcamento.all.each do |empenho|
			if empenho.possui_solicitacoes_de_alteracao_orcamentaria?
				empenho.solicitacoes_de_alteracoes_orcamentarias.destroy_all
			end
			empenho.update_column(:status, 'solicitado')
		end
	end

	def gerar_brasao_em_base64(tamanho=:thumb)
		brasao_file_name = "brasao_temp_file"
		self.brasao.copy_to_local_file(tamanho, brasao_file_name)
		file_temp = File.open(brasao_file_name)
		file_contents = open(file_temp) { |f| f.read }
		file_temp.close
		return 'data:' + brasao.content_type + ';base64,' + Base64.strict_encode64(file_contents)
	end

	def existe_imagem?
		brasao.exists?
	end

	def get_imagem_tipo
		posicao = brasao.content_type.index('/') + 1
		return brasao.content_type[posicao..brasao.content_type.size]
	end

	def get_dimensoes_do_brasao(tamanho=:large)
		if existe_imagem?
			Paperclip::Geometry.from_file(Paperclip.io_adapters.for(brasao))
		end
	end

	def margens_customizadas(params={})
		top = params[:top].to_i
		right = params[:right].to_i
		bottom = params[:top].to_i
		left = params[:left].to_i

		{
			top: customizacao.relatorios_margem_superior + top,
			right: customizacao.relatorios_margem_direita + right,
			bottom: customizacao.relatorios_margem_inferior + bottom,
			left: customizacao.relatorios_margem_esquerda + left
		}
	end

	def expediente
		unless self.horario_inicio_funcionamento_da_prefeitura.blank? && self.horario_fim_funcionamento_da_prefeitura.blank?
			"#{formato_de_horario(self.horario_inicio_funcionamento_da_prefeitura)} às #{formato_de_horario(self.horario_fim_funcionamento_da_prefeitura)}"
		else
			nil
		end
	end

	def parametrizacao_modulos_ordenados_pelo_id
		self.parametrizacao_modulos.order(:id)
	end

	def retorna_modulos_utilizados
		modulos_utilizados = {}
		self.parametrizacao_modulos.select(&:permite_uso_do_modulo?).map do |modulo|
			if modulo.nome_do_modulo != 'transparencia'
				modulos_utilizados.merge!({ modulo.nome_de_exibicao.try(:upcase) => modulo.nome_do_modulo })
			end
		end

		modulos_utilizados
	end

	def usa_modulo_administrativo?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'administrativo').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_contabil?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'contabilidade').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_controle?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'controladoria').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_licitacao?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'licitacao').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_gestao_de_obras?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'obra').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_planejamento?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'planejamento').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_gestao_de_estoque?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'gestao_de_estoque').try(:permite_uso_do_modulo?)
	end

	def usa_modulo_patrimonio?
		self.parametrizacao_modulos.find_by(nome_do_modulo: 'patrimonio').try(:permite_uso_do_modulo?)
	end

	def acesso_bloqueado?
		self.monitorado? && self.data_vencimento_acesso < Date.today
	end

	def dias_que_faltam_para_bloqueio
		if self.monitorado? && self.data_vencimento_acesso.present? && self.data_vencimento_acesso > Date.today
			(self.data_vencimento_acesso - Date.today).to_i
		else
			0
		end
	end

	def responsaveis_atuais_do_SIM(tipo_sim)
		self.configuracoes_sim.where(tipo_sim: tipo_sim).select{ |responsavel| (responsavel.data_de_saida.blank? || responsavel.data_de_saida > Date.today) }
	end

	def existe_responsavel_no_periodo_com_tipo?(data_de_entrada, data_de_saida, tipo_de_responsavel, tipo_de_pessoa, tipo_sim)
		data_de_saida = Date.today if data_de_saida.nil?
		self.configuracoes_sim.joins(:pessoa).where('(data_de_entrada <= ? and data_de_saida >= ?) or (data_de_entrada <= ? and data_de_saida >= ?) or (data_de_entrada < ? and data_de_saida is null)', data_de_entrada, data_de_entrada, data_de_saida, data_de_saida, data_de_saida).where(tipo_de_responsavel: tipo_de_responsavel, tipo_sim: tipo_sim).where('base_pessoas.tipo_de_pessoa_id =? ', tipo_de_pessoa).any?
	end

	def existe_responsavel_no_periodo_sem_tipo?(data_de_entrada, data_de_saida, tipo_de_responsavel, tipo_sim)
		data_de_saida = Date.today if data_de_saida.nil?
		self.configuracoes_sim.where('(data_de_entrada <= ? and data_de_saida >= ?) or (data_de_entrada <= ? and data_de_saida >= ?) or (data_de_entrada < ? and data_de_saida is null)', data_de_entrada, data_de_entrada, data_de_saida, data_de_saida, data_de_saida).where(tipo_de_responsavel: tipo_de_responsavel, tipo_sim: tipo_sim).any?
	end

	def converte_para_string(valor)
		if valor == 1
			valor = 'executivo'
		elsif valor == 2
			valor = 'legislativo'
		else
			valor
		end
	end

	def gestor_responsavel_atual(tipo_de_poder)
		tipo_de_poder = converte_para_string(tipo_de_poder)
		if self.configuracoes_sim.where(tipo_sim: tipo_de_poder).gestor_responsavel.any?
			ConfiguracaoSim.where('tipo_sim = ? and tipo_de_responsavel = ? and data_de_entrada <= ? and (data_de_saida >= ? or data_de_saida is null)', ConfiguracaoSim.tipo_sins[tipo_de_poder], 1, Date.today, Date.today).order(data_de_entrada: :asc).first
		end
	end

	def responsavel_pelo_registro_contabel_atual_PF(tipo_de_poder)
		tipo_de_poder = converte_para_string(tipo_de_poder)
		if self.configuracoes_sim.where(tipo_sim: tipo_de_poder).responsavel_registro_contabel.any?
			ConfiguracaoSim.joins(:pessoa).where('tipo_sim = ? and tipo_de_responsavel = ? and data_de_entrada <= ? and (data_de_saida >= ? or data_de_saida is null) and base_pessoas.cpf is not null', ConfiguracaoSim.tipo_sins[tipo_de_poder], 2, Date.today, Date.today).order(data_de_entrada: :asc).first
		end
	end

	def responsavel_pelo_registro_contabel_atual_PJ(tipo_de_poder)
		tipo_de_poder = converte_para_string(tipo_de_poder)
		if self.configuracoes_sim.where(tipo_sim: tipo_de_poder).responsavel_registro_contabel.any?
			ConfiguracaoSim.joins(:pessoa).where('tipo_sim = ? and tipo_de_responsavel = ? and data_de_entrada <= ? and (data_de_saida >= ? or data_de_saida is null) and base_pessoas.cnpj is not null',ConfiguracaoSim.tipo_sins[tipo_de_poder], 2, Date.today, Date.today).order(data_de_entrada: :asc).first
		end
	end

	def assessor_informatica_atual_PF(tipo_de_poder)
		tipo_de_poder = converte_para_string(tipo_de_poder)
		if self.configuracoes_sim.where(tipo_sim: tipo_de_poder).responsavel_registro_contabel.any?
			ConfiguracaoSim.joins(:pessoa).where('tipo_sim = ? and tipo_de_responsavel = ? and data_de_entrada <= ? and (data_de_saida >= ? or data_de_saida is null) and base_pessoas.cpf is not null', ConfiguracaoSim.tipo_sins[tipo_de_poder], 3, Date.today, Date.today).order(data_de_entrada: :asc).first
		end
	end

	def assessor_informatica_atual_PJ(tipo_de_poder)
		tipo_de_poder = converte_para_string(tipo_de_poder)
		if self.configuracoes_sim.where(tipo_sim: tipo_de_poder).responsavel_registro_contabel.any?
			ConfiguracaoSim.joins(:pessoa).where('tipo_sim = ? and tipo_de_responsavel = ? and data_de_entrada <= ? and (data_de_saida >= ? or data_de_saida is null) and base_pessoas.cnpj is not null',ConfiguracaoSim.tipo_sins[tipo_de_poder], 3, Date.today, Date.today).order(data_de_entrada: :asc).first
		end
	end

	def nome_da_cidade
		self.nome_da_prefeitura.sub(/Prefeitura Municipal de /, '')
	end
	#Validações

	def deve_existir_todos_os_responsaveis(tipo_de_poder)
		(self.gestor_responsavel_atual(tipo_de_poder).blank? or self.responsavel_pelo_registro_contabel_atual_PF(tipo_de_poder).blank? or self.responsavel_pelo_registro_contabel_atual_PJ(tipo_de_poder).blank? or self.assessor_informatica_atual_PF(tipo_de_poder).blank? or self.assessor_informatica_atual_PJ(tipo_de_poder).blank?)
	end

  def valida_gestor_responsavel(tipo_de_poder)
    raise "Necessário cadastrar um Gestor Responsável pela Remessa. " if self.gestor_responsavel_atual(tipo_de_poder).blank?
  end

  def valida_responsavel_registro_contabil_PF(tipo_de_poder)
    raise "Necessário cadastrar um Reponsável pelo Registro Contábil PF. " if self.responsavel_pelo_registro_contabel_atual_PF(tipo_de_poder).blank?
  end

  def valida_responsavel_registro_contabil_PJ(tipo_de_poder)
    raise "Necessário cadastrar um Reponsável pelo Registro Contábil PJ. " if self.responsavel_pelo_registro_contabel_atual_PJ(tipo_de_poder).blank?
  end

  def valida_assessor_informatica_PF(tipo_de_poder)
    raise "Necessário cadastrar um Assessor Informática PF. " if self.assessor_informatica_atual_PF(tipo_de_poder).blank?
  end

  def valida_assessor_informatica_PJ(tipo_de_poder)
    raise "Necessário cadastrar um Assessor Informática PJ. " if self.assessor_informatica_atual_PJ(tipo_de_poder).blank?
  end

	def valida_formatacao_do_email_principal
		unless Truemail.valid?(email_principal_da_autorizacao, with: :regex)
			errors.add(:email_principal_da_autorizacao, 'Email inválido')
		end
	end

	def valida_formatacao_do_email_secundario
		unless Truemail.valid?(email_secundario_da_autorizacao, with: :regex)
			errors.add(:email_secundario_da_autorizacao, 'Email inválido')
		end
	end

	private
	def formato_de_horario horario
		if horario.include?(":")
			horario
		else
			"#{horario}h"
		end
	end

	def apenas_uma_configuracao_cadastrada
		errors[:base] << "Já existe uma configuração cadastrada" if Configuracao.count > 0
	end
end
