class Usuario < ApplicationRecord
	include MantenedorDoOrcamento
	has_paper_trail

	devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, authentication_keys: [:login]

  attr_accessor :concordo
	
	attr_writer :login
	attr_accessor :poder

	attr_default :nivel_de_permissao_a_unidades, 0
	attr_default :aprovado, false
	attr_default :desenvolvedor, false

	belongs_to :perfil
	belongs_to :aprovado_por, class_name: "Usuario", foreign_key: "aprovado_por_id"
	has_one :agente_publico_municipal, class_name:'Base::AgentePublicoMunicipal'
	has_many :mensagens_do_usuario, class_name: 'Comunicacao::MensagemDoUsuario'
	has_many :documentos_do_usuario, class_name: 'DocumentoDoUsuario'
	#has_many :unidades_orcamentarias_por_usuario, class_name: 'Loa::UnidadeOrcamentariaPorUsuario'
	has_one :oauth_application, class_name: "Doorkeeper::Application"

	has_many :access_grants,
					class_name: 'Doorkeeper::AccessGrant',
					foreign_key: :resource_owner_id,
					dependent: :delete_all # or :destroy if you need callbacks

	has_many :access_tokens,
					class_name: 'Doorkeeper::AccessToken',
					foreign_key: :resource_owner_id,
					dependent: :delete_all # or :destroy if you need callbacks

	has_many :tipos_de_unidades_administrativas, lambda { distinct }, through: :unidades_orcamentarias, class_name: 'Base::TipoDeUnidadeAdministrativa'

	before_save :atualiza_unidades_do_usuario
	before_save :atualiza_data_do_termo

	# validates_associated :unidades_orcamentarias_por_usuario
	validates_uniqueness_of :nome_de_usuario, :nome_completo
	validates_presence_of :nome_de_usuario, :nome_completo, :perfil_id, :nivel_de_permissao_a_unidades
	validates_presence_of :cpf, message: 'CPF não pode ficar vazio'

	validate :deve_acessar_todas_as_unidades, if: Proc.new{ self.perfil.present? && (self.perfil.nome.in? ["Setor de Compras", "Comissão de Licitação", "Procuradoria"]) }

	validates :unidades_orcamentarias_por_usuario, uniq_nested_attributes: { atributo: :unidade_orcamentaria_id, mensagem: "Unidade Orçamentária deve ser única para o usuário" }, if: Proc.new{ self.valida_mudanca_em_unidade_orcamentaria }

	validates_cpf :cpf

	validates_uniqueness_of :cpf, if: proc { self.cpf.present? }

	accepts_nested_attributes_for :unidades_orcamentarias_por_usuario, reject_if: :all_blank, allow_destroy: true

	enum nivel_de_permissao_a_unidades: {
		nenhuma_unidade: 0,
		unidades_selecionadas: 1,
		todas_as_unidades: 2
	}

	enum tipo_de_poder: {
			ambos: 1,
			executivo: 2,
			legislativo: 3
	}

	delegate :administrador?, to: :perfil
	delegate :secretario?, to: :perfil
	delegate :setor_de_compras?, to: :perfil
	delegate :comissao?, to: :perfil

	scope :usuarios_por_unidade_orcamentaria, -> (unidade_orcamentaria_id) {
		joins( :unidades_orcamentarias_por_usuario ).where(
			loa_unidades_orcamentarias_por_usuario: {
				unidade_orcamentaria_id: unidade_orcamentaria_id
			}
		)
	}

	scope :nao_aprovados, -> { where("aprovado is false") }
	scope :com_todas_as_unidades, -> { where(nivel_de_permissao_a_unidades: :todas_as_unidades) }

	def login
		@login || self.cpf
	end

	def self.find_for_database_authentication(warden_conditions)
		conditions = warden_conditions.dup
		usuario = Usuario.find_by(cpf: conditions[:login])
		if usuario.present?
			unless usuario.desenvolvedor? && usuario.master?
				conditions.delete(:poder)
			end
		end

		if (login = conditions.delete(:login))
			where(conditions.to_h).where(["cpf = :value", { :value => login.downcase }]).first
		elsif conditions.has_key?(:cpf)
			where(conditions.to_h).first
		end
	end

	def deve_acessar_todas_as_unidades
		unless self.todas_as_unidades?
			errors.add(:nivel_de_permissao_a_unidades, "Usuário com perfil #{perfil.nome} ou devem acessar todas as unidades")
		end
	end

	def deve_informar_o_cpf?
		!self.desenvolvedor? && self.cpf.blank?
	end

	def atualiza_unidades_do_usuario
		if self.todas_as_unidades?
			orcamento = Orcamento.where(exercicio: Date.today.year).first

			if self.executivo?
				unidades = Loa::UnidadeOrcamentaria.joins(orgao: :orcamento).includes(:unidades_orcamentarias_por_usuario).joins(:tipo_de_unidade_administrativa).where('base_tipos_de_unidades_administrativas.poder_associado = 1')
			elsif self.legislativo?
				unidades = Loa::UnidadeOrcamentaria.joins(orgao: :orcamento).includes(:unidades_orcamentarias_por_usuario).joins(:tipo_de_unidade_administrativa).where('base_tipos_de_unidades_administrativas.poder_associado = 0')
			else
				unidades = Loa::UnidadeOrcamentaria.joins(orgao: :orcamento).includes(:unidades_orcamentarias_por_usuario)
			end

			unidades.each do |unidade_orcamentaria|
				self.unidades_orcamentarias_por_usuario.find_or_initialize_by(unidade_orcamentaria_id: unidade_orcamentaria.id)
			end
		elsif self.nivel_de_permissao_a_unidades_changed?
			self.unidades_orcamentarias_por_usuario.delete_all
		end
	end

	def self.authenticate(email, password)
    usuario = Usuario.find_for_authentication(email: email)
    usuario&.valid_password?(password) ? usuario : nil
  end

	def gerar_credenciais
		unless self.oauth_application.present?
			application = Doorkeeper::Application.create(
				name: "#{self.nome_completo}",
				redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
				scopes: "gestao_de_estoques receitas write",
				usuario_id: self.id
			)
		end
	end

	def credencial_api_base64
		self.oauth_application.present? ? Base64.encode64("#{self.oauth_application.try(:uid).try(:strip)}:#{self.oauth_application.try(:secret).try(:strip)}") : ""
	end

	def active_for_authentication?
		super && aprovado?
	end

	def nao_aprovado?
		self.aprovado? ? false : true
	end

	def inactive_message
		aprovado? ? super : :nao_aprovado
	end

	def tem_permisao_ao_poder?
		return true if desenvolvedor?
		poderes_da_unidade = tipos_de_unidades_administrativas.pluck(:poder_associado).uniq
		poderes_da_unidade.include?(poder) #|| poder.eql?('administrador_do_sistema') && master?
		#self.tipo_de_poder.include?(poder) #|| poder.eql?('administrador_do_sistema') && master? -> ajustado pelo Marcos, porém deu erro, voltar a tarefa F#1710 para entender
	end

	def unidades_gestoras_do_exercicio (exercicio)
		data_periodo = Date.new(exercicio, 1, 1)
		
		unidades_gestoras = Loa::UnidadeGestora.where("data_encerramento >= ? or data_encerramento is null", data_periodo).all
	end

	def unidades_gestoras_do_usuario_do_exercicio (exercicio)
		data_periodo = Date.new(exercicio, 1, 1)
		unidades_orcamentarias_ids = self.unidades_orcamentarias_por_usuario.pluck(:unidade_orcamentaria_id)
		unidades_gestoras_das_unidades_orcamentarias = Loa::UnidadeOrcamentaria.where('id in (?)', unidades_orcamentarias_ids).pluck(:unidade_gestora_id)
		
		unidades_gestoras = Loa::UnidadeGestora.where("id in (?) AND (data_encerramento >= ? or data_encerramento is null)", unidades_gestoras_das_unidades_orcamentarias, data_periodo).all
	end

	def atualiza_data_do_termo
		self.data_do_termo = Date.today if self.data_do_termo.nil? && self.concordo == 'true'
	end

	def valida_mudanca_em_unidade_orcamentaria
		unidade_true = []
		self.unidades_orcamentarias_por_usuario.each do |uo|
			unidade_true << uo if uo.changed?
		end
		if unidade_true.any?
			valor_retornado = true
		else
			valor_retornado = false
		end
		
	end

	def verifica_duplicidade_unidade_orcamentaria
		quantidade_unidades =Loa::UnidadeOrcamentariaPorUsuario.find_by_sql("
			select unidade_orcamentaria_id from loa_unidades_orcamentarias_por_usuario where usuario_id = #{self.id}
			group by unidade_orcamentaria_id having count(unidade_orcamentaria_id) > 1 ")
	end
end 