require "webdrivers"

Before do |_scenario|
  @browser = BROWSER.instance
  browser_name = @browser.driver.capabilities[:browser_name]
  browser_version = @browser.driver.capabilities[:version]
  chromedriver_version = @browser.driver.capabilities["chrome"]["chromedriverVersion"]
  Kernel.puts "Using #{browser_name} #{browser_version} with ChromeDriver #{chromedriver_version}"
  @users = Support::UsersCollection.new

  # Set Watir and PageObject global default timeouts
  # Defaults to 60. overridden by @cache_warm build or environment variables
  Watir.default_timeout = 60
  unless ENV["DEFAULT_TIMEOUT"].nil? || ENV["DEFAULT_TIMEOUT"].to_i <= 0
    Watir.default_timeout = ENV["DEFAULT_TIMEOUT"].to_i
  end

  PageObject.default_element_wait = 60
  unless ENV["DEFAULT_ELEMENT_WAIT"].nil? || ENV["DEFAULT_ELEMENT_WAIT"].to_i <= 0
    PageObject.default_element_wait = ENV["DEFAULT_ELEMENT_WAIT"].to_i
  end

  PageObject.default_page_wait = 60
  unless ENV["DEFAULT_PAGE_WAIT"].nil? || ENV["DEFAULT_PAGE_WAIT"].to_i <= 0
    PageObject.default_page_wait = ENV["DEFAULT_PAGE_WAIT"].to_i
  end

  # Duplicating dismiss alert logic in here because if an alert is not caught by a checker
  # (checkers would only catch after a click/page load), we don't want ALL subsequent scenarios to fail
  begin
    @browser.url
  rescue Selenium::WebDriver::Error::UnhandledAlertError
    alert_text = @browser.alert.text
    @browser.alert.ok
    raise "WARNING: Uncaught alert was NOT dismissed by checker! JS alert text: #{alert_text}"
  end
end

Before("@cache_warm") do
  if MISC_SETTINGS[:cache_warm]
    Watir.default_timeout = 180
    PageObject.default_element_wait = 180
    PageObject.default_page_wait = 180
  end
end

Before("not @cache_warm") do
  if MISC_SETTINGS[:cache_warm]
    Watir.default_timeout = 5
    PageObject.default_element_wait = 5
    PageObject.default_page_wait = 5
  end
end

Before("@accounting_run_sanity_check") do
  unless DataHelpers::AccountingPeriodHelper.valid_period_id?(ENV["PERIOD"])
    fail "Cannot run @accounting_run_sanity_check tests unless PERIOD env var is a valid int, e.g. 198"
  end
  @accounting_period = ENV["PERIOD"].to_i
end

Around("@debug_only_glacial_timeout") do |_scenario, block|
  watir_original = Watir.default_timeout
  element_original = PageObject.default_element_wait
  page_original = PageObject.default_page_wait

  Watir.default_timeout = 90
  PageObject.default_element_wait = 90
  PageObject.default_page_wait = 90

  block.call

  Watir.default_timeout = watir_original
  PageObject.default_element_wait = element_original
  PageObject.default_page_wait = page_original
end

# Fails scenario if it's been running for 10 minutes
Around do |_scenario, block|
  Timeout.timeout(600) do
    block.call
  end
end

# rubocop:disable Metrics/BlockLength
# Printing browser logs to the console is currently disabled.
# To enable, uncomment all lines below that contain "browser_logs"
After do |scenario|
  # Print any variable used to current scenario
  Support::Helpers::ScenarioVariables.print_scenario_variables
  # Reset object for next scenario
  Support::Helpers::ScenarioVariables.reset_scenario_variables
  # browser_logs = Support::Logs::Browser.new BROWSER.console_log
  if scenario.passed?
    Kernel.puts(
      "[cucumber]\n"\
      "  Scenario Passed!: #{scenario.location}"
    )
    # browser_logs.print_output unless browser_logs.empty?
  else
    begin
      # Send a runtime "scenario failed" message to STDOUT
      time_stamp = Time.now.strftime("%-l:%M:%S %p on %b %-d, %Y")
      scenario_backtrace = scenario.exception.backtrace.join("\n  ")
      Kernel.puts(
        "[cucumber]\n"\
        "  Scenario failure on #{scenario.location}\n"\
        "  at #{time_stamp}!\n"\
        "  Full backtrace:\n"\
        "  #{scenario_backtrace}"
      )
      # browser_logs.print_output

      # Uncomment lines below to print ORCHARD-FEATURES feature flags to the console on failure
      # feature_cookies = BROWSER.cookies.find_all { |cookie| cookie.include? "features" }
      # features_list = feature_cookies.map { |feature| feature.match(/features\[(.*)\]=(.*)/) }
      # features_message = features_list.inject("") do |message, feature|
      #   message + "  #{feature[1]}: #{feature[2]}\n"
      # end

      # cookies_log_message = if features_list.empty?
      #                         "[cookies]\n"\
      #                         "  No feature cookies found!"
      #                       else
      #                         "[cookies]\n"\
      #                         "  Feature cookies:\n"\
      #                         "#{features_message}"
      #                       end

      # Kernel.puts cookies_log_message
      Kernel.puts "  Failed on #{@browser.url}\n  See cucumber reports for test results"

      # Take a screenshot, embed in the html report
      # used to use Dir.chdir, but this breaks embedding for some stupid reason
      scenario_dir = "FAILED_#{scenario.name.tr(' ', '_').gsub(/[^0-9A-Za-z_]/, '')}_#{Time.stamp}"
      scenario_path = File.join(Support::Paths.logs_root, scenario_dir)
      FileUtils.mkdir_p scenario_path

      screenshot_path = File.join(scenario_path, "screenshot.png")
      if MISC_SETTINGS[:stitched_screenshots]
        @browser.screenshot.save_stitch screenshot_path
      else
        @browser.screenshot.save screenshot_path
      end
      embed(screenshot_path, "image/png")

      source_path = File.join(scenario_path, "source.html")
      page_source = @browser.html
      File.open(source_path, "w") { |f| f.write page_source }

      # Uncomment lines below to print OWS-FEATURES feature flags to the console on failure
      # @users.instance_variables.each do |user_type|
      #   user_type = user_type.to_s.delete("@")
      #   user_type = user_type.to_s.delete('"')
      #   flags = @users.send(user_type).check_user_features
      #   Kernel.puts "================================"
      #   Kernel.puts "Info for user"
      #   Kernel.puts "================================"
      #   user_info = @users.send(user_type).info
      #   user_info.delete(:password)
      #   Kernel.puts user_info
      #   Kernel.puts "================================"
      #   Kernel.puts "Feature Flag status for user"
      #   Kernel.puts "================================"
      #   Kernel.puts flags
      # end
    rescue Selenium::WebDriver::Error::UnknownError, Selenium::WebDriver::Error::WebDriverError
      Kernel.puts "Failed to take a screenshot or get browser url!"\
      " Continuing with the rest of the [After] hook"
    end

    # Kill Cucumber upon first failure if we want fast feedback (FF):
    Cucumber.wants_to_quit = true if MISC_SETTINGS[:fast_feedback]

    # Close and reopen the browser if a test fails. This ensures we don't leak
    # state on a failure, and prevents failures from cascading!
    # Causes cascading failures on the new grid
    if MISC_SETTINGS[:restart_on_failure]
      Kernel.puts "[After hook] Restarting browser because scenario failed!"
      BROWSER.restart
    end
  end

  Support::SplitIOClient.remove_rule_from_split(
    "alw:" + @users.workstation_user_data[:vend_contact_id].to_s
  ) if @users.workstation_user_data
  Support::SplitIOClient.remove_rule_from_split(
    "oa:" + @users.oa_user_data[:id].to_s
  ) if @users.oa_user_data
end
# rubocop:enable Metrics/BlockLength

After("@first_statement_period_change") do
  vendor_id = @accounting_user.info[:id]
  puts "Reverting first_statement_period for #{vendor_id}"
  Support::Helpers::Queries.update_first_statement_period(vendor_id)
end

After("@auth0_reset_user") do
  # first delete user from auth0 service
  Support::Services::OwsUsers.delete_auth0_user(@users.workstation_user_data[:vend_contact_id])
  # then reset db auth0_id
  Support::Services::OwsUsers.reset_auth0_user(@users.workstation_user_data[:vend_contact_id])
end

After("@auth0_reset_single_user") do
  # reset db auth0_id for specific user id
  Support::Services::OwsUsers.reset_auth0_single_user(
    "alw:" + @users.workstation_user_data[:vend_contact_id].to_s
  )
end

Before("@auth0_empty_sms") do
  # before empty all sms's from twilio's account for all sms_numbers found in user_config.yml
  content = YAML.load_file(File.join(Support::Paths.cucumber_root, "features", "yml", "user_config.yml"))
  content[:workstation].each_value do |value|
    if value[:sms_number]
      sms_number = value[:sms_number].to_s.delete(",")
      Support::TwilioClient.delete_all(phone_number: sms_number)
    end
  end
end

Before("@auth0_empty_s3bucket") do
  content = YAML.load_file(File.join(Support::Paths.cucumber_root, "features", "yml", "user_config.yml"))
  content[:workstation].each_value do |value|
    next unless value[:username2]
    Support::S3Client.delete_files(
      bucket: "qa-orcdbucket",
      prefix: "auth0/emails/" + value[:username2].split("@").first
    )
  end
end

Before("@clear_cookies") do
  on(UniversalPage) do |page|
    puts "clearing cookies"
    page.clear_cookies
  end
end

at_exit do
  puts "[at_exit hook] Stopping browser completely."
  BROWSER.stop unless MISC_SETTINGS[:leave_open]
end
