class Steep::Server::SignatureWorker

def active_job?(target, timestamp)

def active_job?(target, timestamp)
  if last_target_validated_at[target] == timestamp
    sleep 0.1
    last_target_validated_at[target] == timestamp
  end
end

def enqueue_target(target:, timestamp:)

def enqueue_target(target:, timestamp:)
  Steep.logger.debug "queueing target #{target.name}@#{timestamp}"
  last_target_validated_at[target] = timestamp
  queue << [target, timestamp]
end

def handle_job(job)

def handle_job(job)
  target, timestamp = job
  if active_job?(target, timestamp)
    validate_signature(target, timestamp: timestamp)
  else
    Steep.logger.info "Skipping signature validation: #{target.name}, queued timestamp=#{timestamp}, latest timestamp=#{last_target_validated_at[target]}"
  end
end

def handle_request(request)

def handle_request(request)
  case request[:method]
  when "initialize"
    # Don't respond to initialize request, but start type checking.
    project.targets.each do |target|
      enqueue_target(target: target, timestamp: Time.now)
    end
  when "textDocument/didChange"
    update_source(request)
    validate_signature_if_required(request)
  end
end

def initialize(project:, reader:, writer:, queue: Queue.new)

def initialize(project:, reader:, writer:, queue: Queue.new)
  super(project: project, reader: reader, writer: writer)
  @queue = queue
  @last_target_validated_at = {}
end

def validate_signature(target, timestamp:)

def validate_signature(target, timestamp:)
  Steep.logger.info "Starting signature validation: #{target.name} (#{timestamp})..."
  target.type_check(target_sources: [], validate_signatures: true)
  Steep.logger.info "Finished signature validation: #{target.name} (#{timestamp})"
  diagnostics = case status = target.status
                when Project::Target::SignatureSyntaxErrorStatus
                  target.signature_files.each.with_object({}) do |(path, file), hash|
                    if file.status.is_a?(Project::SignatureFile::ParseErrorStatus)
                      location = case error = file.status.error
                                 when RBS::Parser::SyntaxError
                                   if error.error_value.is_a?(String)
                                     buf = RBS::Buffer.new(name: path, content: file.content)
                                     RBS::Location.new(buffer: buf, start_pos: buf.content.size, end_pos: buf.content.size)
                                   else
                                     error.error_value.location
                                   end
                                 when RBS::Parser::SemanticsError
                                   error.location
                                 else
                                   raise
                                 end
                      hash[path] =
                        [
                          LSP::Interface::Diagnostic.new(
                            message: file.status.error.message,
                            severity: LSP::Constant::DiagnosticSeverity::ERROR,
                            range: LSP::Interface::Range.new(
                              start: LSP::Interface::Position.new(
                                line: location.start_line - 1,
                                character: location.start_column,
                              ),
                              end: LSP::Interface::Position.new(
                                line: location.end_line - 1,
                                character: location.end_column
                              )
                            )
                          )
                        ]
                    else
                      hash[path] = []
                    end
                  end
                when Project::Target::SignatureValidationErrorStatus
                  error_hash = status.errors.group_by {|error| error.location.buffer.name }
                  target.signature_files.each_key.with_object({}) do |path, hash|
                    errors = error_hash[path] || []
                    hash[path] = errors.map do |error|
                      LSP::Interface::Diagnostic.new(
                        message: StringIO.new.tap {|io| error.puts(io) }.string.split(/\t/, 2).last,
                        severity: LSP::Constant::DiagnosticSeverity::ERROR,
                        range: LSP::Interface::Range.new(
                          start: LSP::Interface::Position.new(
                            line: error.location.start_line - 1,
                            character: error.location.start_column,
                            ),
                          end: LSP::Interface::Position.new(
                            line: error.location.end_line - 1,
                            character: error.location.end_column
                          )
                        )
                      )
                    end
                  end
                when Project::Target::TypeCheckStatus
                  target.signature_files.each_key.with_object({}) do |path, hash|
                    hash[path] = []
                  end
                else
                  Steep.logger.info "Unexpected target status: #{status.class}"
                end
  diagnostics.each do |path, diags|
    writer.write(
      method: :"textDocument/publishDiagnostics",
      params: LSP::Interface::PublishDiagnosticsParams.new(
        uri: URI.parse(project.absolute_path(path).to_s).tap {|uri| uri.scheme = "file"},
        diagnostics: diags
      )
    )
  end
end

def validate_signature_if_required(request)

def validate_signature_if_required(request)
  path = source_path(URI.parse(request[:params][:textDocument][:uri]))
  project.targets.each do |target|
    if target.signature_file?(path)
      enqueue_target target: target, timestamp: Time.now
    end
  end
end