class Tryouts::TestRunner

def apply_framework_defaults(options)

def apply_framework_defaults(options)
  framework_defaults = FRAMEWORK_DEFAULTS[options[:framework]] || {}
  framework_defaults.merge(options)
end

def handle_file_error(exception)

def handle_file_error(exception)
  @status       = :error
  Tryouts.debug "TestRunner#process_file: An error occurred processing #{file}: #{ex.message}"
  error_message = "Batch execution failed: #{exception.message}"
  backtrace     = exception.respond_to?(:backtrace) ? exception.backtrace : nil
  @output_manager&.error(error_message, backtrace)
end

def initialize(files:, options:, output_manager:)

def initialize(files:, options:, output_manager:)
  @files          = files
  @options        = apply_framework_defaults(options)
  @output_manager = output_manager
  @translator     = initialize_translator
  @global_tally   = initialize_global_tally
end

def initialize_global_tally

def initialize_global_tally
  {
    total_tests: 0,
    total_failed: 0,
    total_errors: 0,
    file_count: 0,
    start_time: Time.now,
    successful_files: 0,
    failure_collector: FailureCollector.new,
  }
end

def initialize_translator

def initialize_translator
  return nil if @options[:framework] == :direct
  FRAMEWORKS[@options[:framework]].new
end

def log_run_info

def log_run_info
  @output_manager.processing_phase(@files.size)
  @output_manager.info "Framework: #{@options[:framework]}", 1
  @output_manager.info "Context: #{@options[:shared_context] ? 'shared' : 'fresh'}", 1
  @files.each_with_index do |file, idx|
    @output_manager.info "#{idx + 1}/#{@files.size}: #{Console.pretty_path(file)}", 1
  end
end

def process_file(file)

def process_file(file)
  file = FileProcessor.new(
    file: file,
    options: @options,
    output_manager: @output_manager,
    translator: @translator,
    global_tally: @global_tally,
  )
  file.process
rescue StandardError => ex
  handle_file_error(ex)
  @global_tally[:total_errors] += 1
  1
end

def process_files

def process_files
  failure_count = 0
  @files.each_with_index do |file, _idx|
    result         = process_file(file)
    failure_count += result unless result.zero?
    status         = result.zero? ? Console.color(:green, 'PASS') : Console.color(:red, 'FAIL')
    @output_manager.info "#{status} #{Console.pretty_path(file)} (#{result} failures)", 1
  end
  failure_count
end

def run

def run
  log_run_info
  validate_framework
  result = process_files
  show_failure_summary
  show_grand_total if @global_tally[:file_count] > 1
  result
end

def show_failure_summary

def show_failure_summary
  # Show failure summary if any failures exist
  if @global_tally[:failure_collector].any_failures?
    @output_manager.batch_summary(@global_tally[:failure_collector])
  end
end

def show_grand_total

def show_grand_total
  elapsed_time = Time.now - @global_tally[:start_time]
  @output_manager.grand_total(
    @global_tally[:total_tests],
    @global_tally[:total_failed],
    @global_tally[:total_errors],
    @global_tally[:successful_files],
    @global_tally[:file_count],
    elapsed_time,
  )
end

def validate_framework

def validate_framework
  unless @options[:framework] == :direct || FRAMEWORKS.key?(@options[:framework])
    raise ArgumentError, "Unknown framework: #{@options[:framework]}. Available: #{FRAMEWORKS.keys.join(', ')}, direct"
  end
end