require 'active_support/concern'
require 'active_support/core_ext'

# SessionAuthentication adds session authentication to a controller.
# It includes helper methods for views and a signin_required method to use
# in a before_filter to ensure a request is by a signed in user.
module SessionAuthentication
  extend ActiveSupport::Concern

  included do
    helper_method :current_user, :signed_in?

    before_filter :signin_required
  end

  # Public: Returns the current user or kicks off authentication.
  #
  # Returns a User or NilClass.
  def current_user
    return @current_user if defined?(@current_user)

    self.current_user = user_from_session
  end

  # Internal: Set the current user and add to session.
  #
  # user - The user object you would like to make the current user.
  def current_user=(user)
    return unless user.present?

    @current_user = user
    session[:user_id] = user.id
  end

  # Public: Sign in the user and redirect to the saved url or root path.
  #
  # user - The user object you would like to make the current user.
  def sign_in_and_redirect(user)
    self.current_user = user
    redirect_to session[:return_to] || root_path
  end

  # Public: Validates signed in state.
  #
  # Returns a TrueClass or FalseClass.
  def signed_in?
    !!current_user
  end

  # Public: Require that the the user making the request is signed in.
  def signin_required
    signed_in? || permission_denied
  end

  # Public: Treat the web request or api request as unauthorized.
  def permission_denied
    session[:return_to] = request.path if request.path
    redirect_to "/auth/githubteammember"
  end

  # Internal: Attempt to find user from session if session[:user_id] is present.
  #
  # Returns a User or NilClass.
  def user_from_session
    session[:return_to] = request.path if request.path

    user_finder.find_by_id(session[:user_id]) if session[:user_id].present?
  end

  # Internal: Accessing the user finder through this method
  # allows us to test the interaction more easily
  def user_finder
    @user_finder ||= User
  end

  # Internal: Set user finder to an alternative source.
  attr_writer(:user_finder)
end