class Rs::OauthController < ApplicationController
  before_action :require_signed_in_with_username, only: :new
  before_action :authenticate_user!, only: :create

  def new
    @user          = User.where(cn: params[:username].downcase, ou: Setting.primary_domain).first
    @scopes        = parse_scopes params[:scope]
    @redirect_uri  = params[:redirect_uri]
    @client_id     = params[:client_id]
    @state         = params[:state]
    @root_access_requested = (@scopes & [":r",":rw"]).any?

    @denial_url = url_with_state("#{@redirect_uri}#error=access_denied", @state)

    @expire_at_dates = [["Never", nil],
                        ["In 1 month", 1.month.from_now],
                        ["In 1 day", 1.day.from_now]]

    http_status :bad_request and return unless @redirect_uri.present?

    unless current_user == @user
      sign_out :user

      redirect_to new_rs_oauth_url(@user.cn,
                                   scope: params[:scope],
                                   redirect_uri: params[:redirect_uri],
                                   client_id: params[:client_id],
                                   state: params[:state])
      return
    end

    unless @client_id.present?
      redirect_to(url_with_state("#{@redirect_uri}#error=invalid_request", @state),
                  allow_other_host: true) and return
    end

    if @scopes.empty?
      redirect_to(url_with_state("#{@redirect_uri}#error=invalid_scope", @state),
                  allow_other_host: true) and return
    end

    unless hostname_of(@client_id) == hostname_of(@redirect_uri)
      redirect_to(url_with_state("#{@redirect_uri}#error=invalid_client", @state),
                  allow_other_host: true) and return
    end

    @client_id.gsub!(/http(s)?:\/\//, "")

    if auth = current_user.remote_storage_authorizations.valid.where(permissions: @scopes, client_id: @client_id).first
      redirect_to(url_with_state("#{@redirect_uri}#access_token=#{auth.token}", @state),
                  allow_other_host: true) and return
    end
  end

  def create
    unless current_user.id.to_s == params[:user_id]
      Rails.logger.info("NO MATCH: #{params[:user_id]}, #{current_user.id}")
      http_status :forbidden and return
    end

    permissions  = parse_scopes params[:scope]
    redirect_uri = params[:redirect_uri].presence
    client_id    = params[:client_id].presence
    state        = params[:state].presence
    expire_at    = params[:expire_at].presence

    http_status :bad_request and return unless redirect_uri.present?

    if permissions.empty?
      redirect_to(url_with_state("#{redirect_uri}#error=invalid_scope", state),
                  allow_other_host: true) and return
    end

    unless client_id.present?
      redirect_to(url_with_state("#{redirect_uri}#error=invalid_request", state),
                  allow_other_host: true) and return
    end

    unless hostname_of(client_id) == hostname_of(redirect_uri)
      redirect_to(url_with_state("#{redirect_uri}#error=invalid_client", state),
                  allow_other_host: true) and return
    end

    client_id.gsub!(/http(s)?:\/\//, "")

    auth = current_user.remote_storage_authorizations.create!(
      permissions: permissions,
      client_id: client_id,
      redirect_uri: redirect_uri,
      app_name: client_id,
      expire_at: expire_at
    )

    redirect_to url_with_state("#{redirect_uri}#access_token=#{auth.token}", state),
                allow_other_host: true
  end

  private

  def require_signed_in_with_username
    unless user_signed_in?
      session[:user_return_to] = request.url
      redirect_to new_user_session_path(cn: params[:username], ou: Setting.primary_domain)
    end
  end

  def hostname_of(uri)
    uri.gsub(/http(s)?:\/\//, "").split(":")[0].split("/")[0]
  end

  def parse_scopes(scope_string)
    return [] if scope_string.blank?

    scopes = scope_string.
      gsub(/\[|\]/, "").
      gsub(/\,/, " ").
      gsub(/\/:/, ":").
      split(/\s/).map(&:strip).
      reject(&:empty?)

    scopes = [":r"] if scopes.include?("*:r")
    scopes = [":rw"] if scopes.include?("*:rw")

    scopes
  end

  def url_with_state(url, state)
    state ? "#{url}&state=#{CGI.escape(state)}" : url
  end

end
