# frozen_string_literal: true

require "autospec/rspec_runner"

module Autospec
  class SimpleRunner < RspecRunner
    def initialize
      @mutex = Mutex.new
    end

    def run(specs)
      puts "Running Rspec: #{specs}"
      # kill previous rspec instance
      @mutex.synchronize { self.abort }
      # we use our custom rspec formatter
      args = ["-r", "#{File.dirname(__FILE__)}/formatter.rb", "-f", "Autospec::Formatter"]

      command =
        begin
          line_specified = specs.split.any? { |s| s =~ /\:/ } # Parallel spec can't run specific line
          multiple_files = specs.split.count > 1 || specs == "spec" # Only parallelize multiple files
          if ENV["PARALLEL_SPEC"] == "1" && multiple_files && !line_specified
            "bin/turbo_rspec #{args.join(" ")} #{specs.split.join(" ")}"
          else
            "bin/rspec #{args.join(" ")} #{specs.split.join(" ")}"
          end
        end

      # launch rspec
      Dir.chdir(Rails.root) do # rubocop:disable Discourse/NoChdir because this is not part of the app
        env = { "RAILS_ENV" => "test" }
        if specs.split(" ").any? { |s| s =~ %r{\A(./)?plugins} }
          env["LOAD_PLUGINS"] = "1"
          puts "Loading plugins while running specs"
        end
        pid = @mutex.synchronize { @pid = Process.spawn(env, command) }

        _, status = Process.wait2(pid)

        status.exitstatus
      end
    end

    def abort
      if pid = @pid
        begin
          Process.kill("TERM", pid)
        rescue StandardError
          nil
        end
        wait_for_done(pid)
        pid = nil
      end
    end

    def stop
      # assume sigint on child will take care of this?
      if pid = @pid
        wait_for_done(pid)
      end
    end

    def wait_for_done(pid)
      i = 3000
      while (
              begin
                i > 0 && Process.getpgid(pid)
              rescue StandardError
                nil
              end
            )
        sleep 0.001
        i -= 1
      end
      if (
           begin
             Process.getpgid(pid)
           rescue StandardError
             nil
           end
         )
        STDERR.puts "Terminating rspec #{pid} by force cause it refused graceful termination"
        Process.kill("KILL", pid)
      end
    end
  end
end