module Matchers
  class BroadcastToUser
    class TestBroadcaster
      attr_reader :broadcasts

      def initialize
        @broadcasts = []
      end

      def broadcast(object)
        self.broadcasts << object
      end
    end

    def initialize(user_id)
      @user_id = user_id
      @user_id = @user_id.id if @user_id.is_a?(User)
    end

    def matches?(block)
      old_broadcaster = Qwaiter.broadcaster
      test_broadcaster = TestBroadcaster.new
      Qwaiter.broadcaster = test_broadcaster
      block.call
      Qwaiter.broadcaster = old_broadcaster

      relevant_broadcasts = test_broadcaster.broadcasts.select{|b| b[:channel] =~ /^\/user\/#{@user_id}/ && b[:data][:event] == @message}
      @failure_message = "User #{@user_id} did not receive any broadcasts" and return false if relevant_broadcasts.empty?
      @failure_debug_content = "was #{relevant_broadcasts.map{|b| b[:data][:data].inspect}.join(" and ")}"
      relevant_broadcasts.any? { |b| @target_object === b[:data][:data].deep_symbolize_keys }
    end

    def message(msg)
      @message = msg
      self
    end

    def with(target_object)
      @target_object = target_object
      self
    end

    def failure_message
      @failure_message || "user #{@user_id} did not receive broadcast #{@message} with #{@target_object.inspect} #{@failure_debug_content}"
    end
    def supports_block_expectations?; true; end
  end

  def broadcast_to_user(*args, &block)
    BroadcastToUser.new(*args, &block)
  end
end
