require "require_all"
require "byebug"
require_relative "../../support/paths"
require_relative "../../support/entry_point"
require_relative "../../support/formatters/timestamped_json"
require_rel "run"
require_rel "."

module Cuke
  class TaskRunner
    def initialize(**keywords)
      @keywords = {
        files: ["features/"],
        parallel: true,
        with_rerun: true,
        cucumber_opts: [],
        parallel_opts: {},
        minimal_run: false,
        profile: nil
      }.merge(keywords)
      @keywords.each { |key, val| instance_variable_set("@#{key}", val) }
      start
    end

    def instantiate_runs
      add_profile_to_opts

      @first_run = if @minimal_run
                     Cuke::Run::Minimal.new(@keywords)
                   elsif @parallel
                     Cuke::ParallelRuntimeLogs.new.copy_temp_to_actual
                     Cuke::Run::Parallel.new(@keywords)
                   else
                     Cuke::Run::Serial.new(@keywords)
                   end

      @rerun = Cuke::Run::Rerun.new(@keywords) if @with_rerun
    end

    def start
      instantiate_runs
      @cukes_successful = run_successfully?(@first_run)

      if !@cukes_successful && @with_rerun
        rerun_string = IO.read(File.join(Support::Paths.logs_root, "rerun.txt"))
        puts "[rake] First run has a FAILURE! Rerunning the following tests: #{rerun_string}"
        fail "[rake] First run failed but no cukes to rerun!" if rerun_string.gsub(/\s+/, "").empty?

        @rerun_successful = run_successfully?(@rerun)
      end

      print_run_status
    end

    # Begin a Cucumber run and return true if it was successful or false if
    # there were any failures (Cucumber fails with a SystemExit exception if
    # any scenarios fail)
    def run_successfully?(run_instance)
      begin
        run_instance.run
      rescue SystemExit
        return false
      end
      true
    end

    def print_run_status
      if @cukes_successful
        puts "[rake] First run was a SUCCESS!"
        Cuke::ParallelRuntimeLogs.new.move_actual_to_temp if @parallel
      elsif @rerun_successful
        puts "[rake] Rerun was a SUCCESS!"
      elsif !@cukes_successful && !@with_rerun
        fail "[rake] First run has a FAILURE and no rerun was desired! Marking build as FAILED."
      else
        fail "[rake] Rerun has a FAILURE! Marking entire build as FAILED."
      end
    end

    def add_profile_to_opts
      fail "You requested Cucumber to run with profile #{@profile}"\
        " but the profile does not exist in cucumber.yml!" unless profile_exists?(@profile)
      profile_opt = %W[-p #{@profile}]
      @keywords[:cucumber_opts].unshift(*profile_opt) # so `-p profile` is first opt passed to cucumber exec
    end

    def profile_exists?(name)
      require "cucumber/cli/profile_loader"
      Cucumber::Cli::ProfileLoader.new.has_profile?(name)
    end
  end
end
