require './core/base/page_helper'
require './core/utils/stats_utils'
require './core/configs/environment/web_environment'
require './core/twitch/web/components/top_nav'

# Helpers Pertaining to LoginPage
module LoginPage
  include StatUtils
  # TODO: Investigate why we're clearing cookies - Capybara should auto do this after each scenario

  # Standard login method. Visits the login page, fills in fields, and logs in with verification expectations.
  # @param username [String] The username to log in as.
  # @param password [String] The password to log in as.
  def login(username, password)
    visit login_path
    handle_captcha
    fill_in_login_fields(:username => username, :password => password)
    get_login_button.click

    login_error_check()

    wait_time = 5
    expect(page).to have_current_path('/', wait: wait_time) # Expect to navigate to front page. Need wait due to Passport redirects.
    expect(TopNav.element).to have_content username.downcase
  end

  # Fills in fields on /login with the supplied data.
  # Supports not filling in a field to test expectations.
  # @param username [String] The username to log in as.
  # @param password [String] The password to log in as.
  def fill_in_login_fields(username: nil, password: nil)
    within('.card') do
      fill_in('username', :with => username) unless username.nil? || username.empty?
      fill_in('password', :with => password) unless password.nil? || password.empty?
    end
  end

  # A condensed login method that includes no error checking.
  # @param username [String] The username to log in as.
  # @param password [String] The password to log in as.
  def login_reduced(username, password)
    # We want most tests to rely on login() because it gives clear indication to what's going on.
    # Some tests though are meant to fail, in which they use this + their expectations
    visit login_path
    handle_captcha

    fill_in_login_fields(:username => username, :password => password)
    get_login_button.click
  end

  # Logs a user into a modal that has already been opened. Once the modal is showing on screen, this method can be called.
  # @param username [String] The username to log in as.
  # @param password [String] The password to log in as.

  def passport_iframe
    auth_modal_css = '.auth-modal-wrapper'
    within auth_modal_css do
      return find('iframe', wait: 6) # This is Passport. Give it 6 seconds to load
    end
  end

  def login_modal(username, password)
    login_modal_css = '.js-login-popup'
    before_path = current_path # Store the current_path before logging in

    within_frame passport_iframe do
      expect(page).to have_css('#login_tab a', wait: 10, visible: true)

      find('#login_tab a').click
      fill_in('username', :with => username)
      fill_in('password', :with => password)
      find('.primary.button').click
    end

    expect(page).not_to have_css(login_modal_css, wait: 6) # Login Modal should close. Upper bound was found to be 6 seconds.
    expect(page).to have_current_path(before_path, wait: 5) # Expect to be redirected back to the previous path
    login_error_check()
  end

  # A method to check if there was an error thrown upon login.
  # Will then report the error to statsd. Useful for production monitoring.
  def login_error_check
    begin
      expect(page).not_to have_css('.subwindow_notice') # Expect No Error Upon LoginPage
    rescue RSpec::Expectations::ExpectationNotMetError => e
      $login_rate.increment_fail # Increment the failure rate - the login failed
      error = find('.subwindow_notice').text
      puts "Encountered LoginPage Error: #{error}"

      increment("warnings.login.#{return_error_code(error)}") # Reports the error to statsd
      raise "#{e}\nReceived LoginPage Error: #{error}"
    end

    $login_rate.increment_success # If it got here, count it as a success
  end

  # Finds the 'Log In' button on a page and returns its element.
  # @return [Capybara::Node::Element] The login button element.
  def get_login_button
    begin
      return find_button('Log In')
    rescue Exception # Capybara will not pick up a disabled button, so look for a disabled
      return find_button('Log In', disabled: true)
    end
  end

  # @return [String] Path to the login page
  def login_path
    return "#{WebEnvironment.url}/login"
  end

  # Parses a login error for a generalized error code.
  # An error such as 'There was an error logging you in (error code: missing_nonce)' would be 'missing_nonce'.
  # @param message [String] The full error message
  # @return [String] An understandable and reportable error code.
  def return_error_code(message)
    # https://git-aws.internal.justin.tv/web/web/blob/master/app/controllers/passport_controller.rb#L117

    if message == 'Oops! We encountered an unexpected error logging you in. Please try again.'
      return 'unexpected_error_logging_in_rails'
    elsif message == 'Oops! We encountered an unexpected error. Please try again.'
      # Yup, this is a different error than the above. This one is a non-rails errors
      return 'unexpected_error_logging_in'
    elsif message == 'Please enter your username and password.'
      return 'missing_user_or_password'
    else
      regex = /\(error code: (\w+)\)./ # Looks for something like (error code: bad_nonce)
      error_code = (message.match regex)
      return error_code[1] if error_code != nil # It will be nil if there was no match
    end

    return 'unknown_error' # If it got here, it couldn't find the error...
  end

  # @param username [String] The username to search if they are logged in
  # @return [Boolean] If the user is logged in
  def is_logged_in?(username)
    return TopNav.element.has_text?(username.downcase)
  end

  # A simple get method to return the name of the Captcha Bypass cookie, thus reducing hardcoded names
  # @return [String] Cookie name to bypass
  def get_captcha_bypass_cookie_name
    return 'passport_trusted_request'
  end

  # Check if the login page has captcha, bypass it by setting a special cookie.
  # Only works to bypass on the internal network.
  # https://git-aws.internal.justin.tv/web/passport#bypassing-captchas
  def add_bypass_cookie
    PageHelper.add_cookie(get_captcha_bypass_cookie_name, '1')
  end

  # Sets a cookie to bypass captcha
  # Useful for setting this before a scenario
  def set_bypass_captcha_cookie
    visit login_path
    expect(page).to have_css('html') # Wait for the page to load before setting the cookie. SMOC-102
    add_bypass_cookie
  end

  # Recovers from a captcha if it discovers a captcha on the current page.
  # Useful for methods outside of the login spec that need to rely on login.
  def handle_captcha
    if have_css('.g-recaptcha')
      add_bypass_cookie # Allow to log in without captcha
      visit current_url
    end
  end

  def check_incorrect_login_messaging
    expect(page).to have_content('Incorrect username or password.')
  end

end
