require "json"
require_relative "../github"
require_relative "../scripts"

module Octopolo
  module Scripts
    class GithubAuth
      include CLIWrapper
      include UserConfigWrapper

      attr_accessor :username
      attr_accessor :password
      attr_accessor :auth_response
      attr_accessor :user_defined_token

      def self.execute
        new.execute
      end

      def execute
        case ask_auth_method
        when "Generate an API token with my credentials"
          ask_credentials
          request_token
        when "I'll enter an access token manually"
          ask_token
          verify_token
        end
        store_token
      rescue GitHub::BadCredentials => e
        cli.say e.message
      end

      # Private: Give option to manually get token from GitHub and use it instead of using creds (For people that use 2FA)
      def ask_auth_method
        question = "Would you like to generate an GitHub API token with your credentials or enter one manually?\n"\
                   "You *must* enter a token manually if you are using GitHub's Two Factor Authentication.\n"\
                   "For more information, see https://help.github.com/articles/creating-an-access-token-for-command-line-use\n\n"
        choices = ["Generate an API token with my credentials", "I'll enter an access token manually"]
        selected = cli.ask(question, choices)
      end
      private :ask_auth_method

      # Private: Request the user's GitHub username and password
      def ask_credentials
        self.username = cli.prompt "Your GitHub username: "
        self.password = cli.prompt_secret "Your GitHub password (never stored): "
      end
      private :ask_credentials

      # Private: Request an auth token from GitHub
      def request_token
        json = cli.perform_quietly %Q(curl -u '#{username}:#{password}' -d '{"scopes": ["repo"], "notes": "Octopolo"}' https://api.github.com/authorizations)
        self.auth_response = JSON.parse json
      end
      private :request_token

      # Private: Verify a user_defined_token with GitHub
      def verify_token
        json = cli.perform_quietly %Q(curl -u #{user_defined_token}:x-oauth-basic https://api.github.com/user)
        self.auth_response = JSON.parse json
      end
      private :verify_token

      # Private: Request the user to give a token to be set manually (required for 2FA)
      def ask_token
        self.username = cli.prompt "Your GitHub username: "
        self.user_defined_token = cli.prompt_secret "Your GitHub API token: "
      end
      private :ask_token

      # Private: Store the token recieved from GitHub
      #
      # If a token is present in the response, store it in the user config.
      # Otherwise indicate that the authorization did not succeed.
      def store_token
        token = auth_response["login"] ? user_defined_token : auth_response["token"]
        if token
          user_config.set :github_user, username
          user_config.set :github_token, token
          cli.say "Successfully stored GitHub API token."
        else
          raise GitHub::BadCredentials, "Uh oh, your access token couldn't be generated/verified. Please check your credentials and try again."
        end
      end
      private :store_token

    end
  end
end