# Request password change via an emailed link with a unique token.
# Thanks to devise and Clearance.
class Authenticate::PasswordsController < Authenticate::AuthenticateController
  skip_before_action :require_login, only: [:create, :edit, :new, :update], raise: false
  skip_before_action :require_authentication, only: [:create, :edit, :new, :update], raise: false
  before_action :ensure_existing_user, only: [:edit, :update]

  # Display screen to request a password change email.
  # GET /users/passwords/new
  def new
    render template: 'passwords/new'
  end

  # Send password change email.
  #
  # POST /users/password
  def create
    if (user = find_user_for_create)
      user.forgot_password!
      deliver_email(user)
    end
    redirect_to sign_in_path, notice: flash_create_description
  end

  # Screen to enter your new password.
  #
  # A get with the token in the url is expected:
  #   GET /users/passwords/3/edit?token=abcdef
  #
  # This results in a redirect with the token removed from the url & copied to the session:
  #   GET /users/passwords/3/edit
  #
  def edit
    @user = find_user_for_edit

    if params[:token]
      session[:password_reset_token] = params[:token]
      redirect_to edit_users_password_url(@user)
    elsif !@user.reset_password_period_valid?
      redirect_to sign_in_path, notice: flash_failure_token_expired
    else
      render template: 'passwords/edit'
    end
  end

  # Save the new password entered in #edit.
  #
  # PUT /users/passwords/3/
  def update
    @user = find_user_for_update

    if !@user.reset_password_period_valid?
      redirect_to sign_in_path, notice: flash_failure_token_expired
    elsif @user.update_password password_reset_params # password changed, log user back in!
      login @user
      redirect_to url_after_update, notice: flash_success_password_changed
    else
      # failed to update password for some reason, perhaps password was too short or otherwise sucked.
      flash.now[:notice] = flash_failure_after_update
      render template: 'passwords/edit'
    end
  end

  private

  def deliver_email(user)
    mail = ::AuthenticateMailer.change_password(user)

    if mail.respond_to?(:deliver_later)
      mail.deliver_later
    else
      mail.deliver
    end
  end

  def password_reset_params
    params[:password_reset][:password]
  end

  def find_user_for_create
    Authenticate.configuration.user_model_class.find_by_normalized_email params[:password][:email]
  end

  def find_user_for_edit
    find_user_by_id_and_password_reset_token
  end

  def find_user_for_update
    find_user_by_id_and_password_reset_token
  end

  def ensure_existing_user
    unless find_user_by_id_and_password_reset_token
      flash.now[:notice] = flash_failure_when_forbidden
      render template: 'passwords/new'
    end
  end

  def find_user_by_id_and_password_reset_token
    token = session[:password_reset_token] || params[:token]
    # Authenticate.configuration.user_model_class.where(id: params[:id], password_reset_token: token).first
    Authenticate.configuration.user_model_class.find_by_id_and_password_reset_token params[:id], token.to_s
  end

  def flash_create_description
    translate(:description,
              scope: [:Authenticate, :controllers, :passwords],
              default: t('passwords.create.description'))
  end

  def flash_success_password_changed
    translate(:success_password_changed,
              scope: [:Authenticate, :controllers, :passwords],
              default: t('flashes.success_password_changed'))
  end

  def flash_failure_token_expired
    translate(:failure_token_expired,
              scope: [:Authenticate, :controllers, :passwords],
              default: t('flashes.failure_token_expired'))
  end

  def flash_failure_when_forbidden
    translate(:forbidden,
              scope: [:Authenticate, :controllers, :passwords],
              default: t('flashes.failure_when_forbidden'))
  end

  def flash_failure_after_update
    translate(:blank_password,
              scope: [:Authenticate, :controllers, :passwords],
              default: t('flashes.failure_after_update'))
  end

  def url_after_create
    sign_in_url
  end

  def url_after_update
    Authenticate.configuration.redirect_url
  end
end