class TD::UpdateManager
  TIMEOUT = 30
  attr_reader :handlers, :worker
  attr_accessor :callback

  def initialize(td_client)
    @td_client = td_client
    @handlers = Concurrent::Array.new
    @mutex = Mutex.new
    @worker = nil
    @callback = nil
  end

  def add_handler(handler)
    @mutex.synchronize { @handlers << handler }
  end

  alias << add_handler

  def run()
    @worker = Thread.start do
      catch(:client_closed) { loop { handle_update() } }
      puts 'client_closed'
      @td_client = nil
      @mutex.synchronize { @handlers = [] }
    end
  end

  private

  def handle_update()
    # stats = AllocationStats.trace { # MemoryProfiler.start if $gogo
      update = TD::Api.client_receive(@td_client, TIMEOUT)
      # puts 'manager#handle_update 1'
      unless update.nil?
        # puts 'manager#handle_update 2'
        @callback&.call(update)
        match_handlers!(update) { |h| h.run(update) }
      end
    # }

    # puts stats.allocations(alias_paths: true).group_by(:sourcefile, :sourceline, :class).to_text
    # puts stats.allocations().group_by(:sourcefile, :sourceline, :class).to_text


    # report = MemoryProfiler.stop if $gogo
    # report.pretty_print if $gogo && report
  end

  def match_handlers!(update)
    @mutex.synchronize do
      # handlers.each { |h| h.destroy && handlers.delete(h) if h.resolved? }
      # matched_handlers = handlers.select { |h| h.match?(update, extra) }
      # matched_handlers.each { |h| h.destroy && handlers.delete(h) if h.disposable? }
      # matched_handlers
      # delete resolved handlers
      # puts handlers.count
      handlers.each { |h| h.destroy && handlers.delete(h) if h.resolved? }
      handlers.each { |h|
        if h.match?(update)
          yield h
          h.resolve! if h.disposable?
        end
      }
    end
  end
end
