class Steep::Drivers::Watch

def initialize(stdout:, stderr:)

def initialize(stdout:, stderr:)
  @dirs = []
  @stdout = stdout
  @stderr = stderr
  @queue = Thread::Queue.new
end

def run()

def run()
  if dirs.empty?
    stdout.puts "Specify directories to watch"
    return 1
  end
  project = load_config()
  loader = Project::FileLoader.new(project: project)
  loader.load_sources(dirs)
  loader.load_signatures()
  client_read, server_write = IO.pipe
  server_read, client_write = IO.pipe
  client_reader = LanguageServer::Protocol::Transport::Io::Reader.new(client_read)
  client_writer = LanguageServer::Protocol::Transport::Io::Writer.new(client_write)
  server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
  server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)
  interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path)
  signature_worker = Server::WorkerProcess.spawn_worker(:signature, name: "signature", steepfile: project.steepfile_path)
  code_workers = Server::WorkerProcess.spawn_code_workers(steepfile: project.steepfile_path)
  master = Server::Master.new(
    project: project,
    reader: server_reader,
    writer: server_writer,
    interaction_worker: interaction_worker,
    signature_worker: signature_worker,
    code_workers: code_workers
  )
  main_thread = Thread.start do
    master.start()
  end
  main_thread.abort_on_exception = true
  client_writer.write(method: "initialize", id: 0)
  Steep.logger.info "Watching #{dirs.join(", ")}..."
  listener = Listen.to(*dirs.map(&:to_s)) do |modified, added, removed|
    stdout.puts "🔬 Type checking updated files..."
    version = Time.now.to_i
    Steep.logger.tagged "watch" do
      Steep.logger.info "Received file system updates: modified=[#{modified.join(",")}], added=[#{added.join(",")}], removed=[#{removed.join(",")}]"
      (modified + added).each do |path|
        client_writer.write(
          method: "textDocument/didChange",
          params: {
            textDocument: {
              uri: "file://#{path}",
              version: version
            },
            contentChanges: [
              {
                text: Pathname(path).read
              }
            ]
          }
        )
      end
      removed.each do |path|
        client_writer.write(
          method: "textDocument/didChange",
          params: {
            textDocument: {
              uri: "file://#{path}",
              version: version
            },
            contentChanges: [
              {
                text: ""
              }
            ]
          }
        )
      end
    end
  end.tap(&:start)
  begin
    stdout.puts "👀 Watching directories, Ctrl-C to stop."
    client_reader.read do |response|
      case response[:method]
      when "textDocument/publishDiagnostics"
        uri = URI.parse(response[:params][:uri])
        path = project.relative_path(Pathname(uri.path))
        diagnostics = response[:params][:diagnostics]
        unless diagnostics.empty?
          diagnostics.each do |diagnostic|
            start = diagnostic[:range][:start]
            loc = "#{start[:line]+1}:#{start[:character]}"
            message = diagnostic[:message].chomp.lines.join("  ")
            stdout.puts "#{path}:#{loc}: #{message}"
          end
        end
      end
    end
  rescue Interrupt
    stdout.puts "Shutting down workers..."
    client_writer.write({ method: :shutdown, id: 10000 })
    client_writer.write({ method: :exit })
    client_writer.io.close()
  end
  listener.stop
  main_thread.join
  0
end