require 'spec_helper'
require 'thread'

LoginClient = Class.new do
  attr_accessor :onmsgblock, :onopenblock, :encode_json, :client_id


  def initialize()

  end

  def onopen(&block)
    @onopenblock = block
  end

  def onmessage(&block)
    @onmsgblock = block
  end

  def close(&block)
    @oncloseblock = block
  end

  def close_websocket()

  end

  def send(msg)
    puts msg
  end

  def get_peername
    return "\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" # 37643, "localhost"
  end

end


# does a login and returns client
def login(router, user, password, client_id)

  message_factory = MessageFactory.new
  client = LoginClient.new

  login_ack = message_factory.login_ack("127.0.0.1", client_id, user.remember_token, 15, nil, false)

  router.should_receive(:send_to_client) do |*args| 
    args.count.should == 2
    args[0].should == client
    args[1].is_a?(Jampb::ClientMessage).should be_true
  end
  router.should_receive(:extract_ip).at_least(:once).with(client).and_return("127.0.0.1")
  client.should_receive(:onclose)
  client.should_receive(:onerror)

  #client.should_receive(:get_peername).and_return("\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00")

  @router.new_client(client)
  handshake = double("handshake")
  handshake.should_receive(:query).and_return({ "pb" => "true" })
  client.onopenblock.call handshake

  # create a login message, and pass it into the router via onmsgblock.call
  login = message_factory.login_with_user_pass(user.email, password, :client_id => client_id)

  # first log in
  client.onmsgblock.call login.to_s

  # then join music session
  return client
end

# currently commented out; we have deprecated logging in for jam sessions via websocket-gateway;
# use rest API instead (or direct db access with factory-girl)
def login_music_session(router, client, music_session)
  #message_factory = MessageFactory.new
  #login_music_session = message_factory.login_music_session(music_session.id)
  #login_ack = message_factory.login_music_session_ack(false, nil);
  #router.should_receive(:send_to_client).with(client, login_ack)
  #client.onmsgblock.call login_music_session.to_s
end


describe Router do 
  include EventedSpec::EMSpec

  message_factory = MessageFactory.new

  em_before do
    @router = Router.new()
  end

  subject { @router }

  em_after do

  end


  describe "serviceability" do
    it "should start and stop", :mq => true do
      #em do
        done
      #end
    end

    it "should register for client events", :mq => true do
      #em do
        client = double("client")
        client.should_receive(:onopen)
        client.should_receive(:onclose)
        client.should_receive(:onerror)
        client.should_receive(:onmessage)
        client.should_receive(:encode_json=)

        @router.new_client(client)
        done
      #end
    end
  end

  describe "topic routing helpers" do
    it "create and delete user lookup set" do
      #em do
        user = double(User)
        user.should_receive(:id).any_number_of_times.and_return("1")
        client = double("client")
        context = ClientContext.new(user, client)

        @router.user_context_lookup.length.should == 0

        @router.add_user(context)

        @router.user_context_lookup.length.should == 1

        @router.remove_user(context)

        @router.user_context_lookup.length.should == 0
        done
      #end
    end
  end


  describe "login" do
    it "should not allow login of bogus user", :mq => true do
      #em do
        TestClient = Class.new do

          attr_accessor :onmsgblock, :onopenblock, :encode_json, :client_id

          def initialize()

          end

          def onopen(&block)
            @onopenblock = block
          end

          def onmessage(&block)
            @onmsgblock = block
          end

          def close_websocket()
          end

          def close()
          end
        end

        client = TestClient.new

        error_msg = message_factory.server_rejection_error("invalid login")

        @router.should_receive(:send_to_client).with(client, error_msg)
        client.should_receive(:close_websocket)
        client.should_receive(:onclose)
        client.should_receive(:onerror)


        @router.new_client(client)
        handshake = double("handshake")
        handshake.should_receive(:query).and_return({"pb" => "true"})
        client.onopenblock.call handshake

        # create a login message, and pass it into the router via onmsgblock.call
        login = message_factory.login_with_user_pass("baduser@example.com", "foobar")

        client.onmsgblock.call login.to_s
        done
      #end
    end

    it "should allow login of valid user", :mq => true do
      #em do
        @user = FactoryGirl.create(:user, 
                         :password => "foobar", :password_confirmation => "foobar")
        client1 = login(@router, @user, "foobar", "1")
        done
      #end
    end

    it "should allow music_session_join of valid user", :mq => true do
      #em do
        user1 = FactoryGirl.create(:user) # in the music session
        user2 = FactoryGirl.create(:user) # in the music session
        user3 = FactoryGirl.create(:user) # not in the music session

        music_session = FactoryGirl.create(:music_session, :creator => user1)

        music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :client_id => "4")
        music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :client_id => "5")

        # make a music_session and define two members

        # create client 1, log him in, and log him in to music session
        client1 = login(@router, user1, "foobar", "1")
        login_music_session(@router, client1, music_session)
        done
      #end
    end

    it "should allow two valid subscribers to communicate with session-directed messages", :mq => true do
      #em do
        user1 = FactoryGirl.create(:user) # in the music session
        user2 = FactoryGirl.create(:user) # in the music session

        music_session = FactoryGirl.create(:music_session, :creator => user1)


        # create client 1, log him in, and log him in to music session
        client1 = login(@router, user1, "foobar", "1")
        login_music_session(@router, client1, music_session)

        client2 = login(@router, user2, "foobar", "2")
        login_music_session(@router, client2, music_session)

        # make a music_session and define two members

        music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :client_id => "6")
        music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :client_id => "7")

        done
      #end
    end

    it "should allow two valid subscribers to communicate with p2p messages", :mq => true do
      #em do
          user1 = FactoryGirl.create(:user) # in the music session
          user2 = FactoryGirl.create(:user) # in the music session

          music_session = FactoryGirl.create(:music_session, :creator => user1)

          # create client 1, log him in, and log him in to music session
          client1 = login(@router, user1, "foobar", "1")
          #login_music_session(@router, client1, music_session)

          client2 = login(@router, user2, "foobar", "2")
          #login_music_session(@router, client2, music_session)

          # by creating
          music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :client_id => "8")

          # now attempt to message p2p!

          # first test: user 2 should be able to send a ping message to user 1, even though he isn't in the same session yet

          # create a login message, and pass it into the router via onmsgblock.call
          ping = message_factory.ping_request("1", "2")

          #@router.should_receive(:send_to_client) #.with(client1, ping)

          ## send ping to client 2
          #client2.onmsgblock.call ping.to_s

          #music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :client_id => "2")

          done
      #end
    end
  end
end

