   end
 
   @timeout round(Application.get_env(:mia_server, :timeout) * 1.25)
+  @players 2
+  @spectators 1
 
   defp open_udp_socket(ip) do
     opts = [:binary, active: false, ip: ip]

  defp make_nonsense_msg(token), do: "BLABLA;#{token}"
  defp make_announcement_msg(token, d1, d2), do: "ANNOUNCE;#{d1},#{d2};#{token}"
  defp make_see_msg(token), do: "SEE;#{token}"
  
  defp do_see(socket, port, player, sockets) do
    socket
      |> receive_message()
      |> check_and_gettoken(:yourturn)
      |> make_see_msg()
      |> send_to_server(socket, port)
    check_broadcast_message(sockets, "PLAYER WANTS TO SEE;#{player}\n")
  end
  
  defp do_roll(socket, port, player, sockets) do
    socket
      |> receive_message()
      |> check_and_gettoken(:yourturn)
      |> make_roll_msg()
      |> send_to_server(socket, port)
    check_broadcast_message(sockets, "PLAYER ROLLS;#{player}\n")
  end

  defp do_announcement(socket, port, player, d1, d2, sockets) do
    socket
      |> receive_message()
      |> check_and_gettoken(:rolled)
      |> make_announcement_msg(d1,d2)
      |> send_to_server(socket, port)
    check_broadcast_message(sockets, "ANNOUNCED;#{player};#{d1},#{d2}\n")
  end

  test "First player receives Your Turn" do
    {startmsg, sockets, ports} = setup_game()
    {turn, _players, [socket | _], _ports} = extract_player_seq(startmsg, sockets, ports)
    assert turn == 1
    socket |> receive_message() |> check_and_gettoken(:yourturn)
  end

  test "First player rolls and receives dice" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
    do_roll(socket, port, player, sockets)
    socket |> receive_message() |> check_and_gettoken(:rolled)
  end

  test "First player does nothing" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player | _], [socket | _], _} = extract_player_seq(startmsg, sockets, ports)
    receive_message(socket)
    Process.sleep(@timeout)
    check_player_lost_aftermath(player, sockets, "DID NOT TAKE TURN")
  end

  test "Player sends invalid command" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
    socket
      |> receive_message()
      |> check_and_gettoken(:yourturn)
      |> make_nonsense_msg()
      |> send_to_server(socket, port)
    check_player_lost_aftermath(player, sockets, "INVALID TURN")
  end

  test "Player rolls but fails to announce" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
    do_roll(socket, port, player, sockets)
    receive_message(socket)
    Process.sleep(@timeout)
    check_player_lost_aftermath(player, sockets, "DID NOT ANNOUNCE")
  end

  test "Game round with consecutive announcements" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
    MiaServer.Game.testing_inject_dice(3,1)
    do_roll(socket1, port1, player1, sockets)
    do_announcement(socket1, port1, player1, 3, 1, sockets)
    # Second players turn
    MiaServer.Game.testing_inject_dice(3,2)
    do_roll(socket2, port2, player2, sockets)
    do_announcement(socket2, port2, player2, 4, 1, sockets)
    # Again first players turn
    socket1 |> receive_message() |> check_and_gettoken(:yourturn)
  end

  test "Player announces lower dice" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
    MiaServer.Game.testing_inject_dice(6,1)
    do_roll(socket1, port1, player1, sockets)
    do_announcement(socket1, port1, player1, 6, 1, sockets)
    # Second players turn
    MiaServer.Game.testing_inject_dice(3,2)
    do_roll(socket2, port2, player2, sockets)
    do_announcement(socket2, port2, player2, 5, 1, sockets)
    check_player_lost_aftermath(player2, sockets, "ANNOUNCED LOSING DICE")
  end

  test "Player announces invalid MIA" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player1 | _], [socket1 | _], [port1 | _]} = extract_player_seq(startmsg, sockets, ports)
    MiaServer.Game.testing_inject_dice(6,1)
    do_roll(socket1, port1, player1, sockets)
    do_announcement(socket1, port1, player1, 2, 1, sockets)
    check_player_lost_aftermath(player1, sockets, "LIED ABOUT MIA")
  end

  test "Player announces valid MIA" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player1, player2 | _], [socket1 | _], [port1 | _]} = extract_player_seq(startmsg, sockets, ports)
    MiaServer.Game.testing_inject_dice(2,1)
    do_roll(socket1, port1, player1, sockets)
    do_announcement(socket1, port1, player1, 2, 1, sockets)
    check_player_lost_aftermath(player2, sockets, "MIA")
  end
  
  test "Player wants to see, but no previous roll was made" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
    do_see(socket, port, player, sockets)
    check_player_lost_aftermath(player, sockets, "SEE BEFORE FIRST ROLL")
  end

  test "Player wants to see, but roll was correctly annnounced" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
    MiaServer.Game.testing_inject_dice(6,1)
    do_roll(socket1, port1, player1, sockets)
    do_announcement(socket1, port1, player1, 5, 1, sockets)
    # Second players turn
    do_see(socket2, port2, player2, sockets)
    check_player_lost_aftermath(player2, sockets, "SEE FAILED")
  end

  test "Player wants to see, and previous player bluffed" do
    {startmsg, sockets, ports} = setup_game()
    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
    MiaServer.Game.testing_inject_dice(5,1)
    do_roll(socket1, port1, player1, sockets)
    do_announcement(socket1, port1, player1, 6, 1, sockets)
    # Second players turn
    do_see(socket2, port2, player2, sockets)
    check_player_lost_aftermath(player1, sockets, "CAUGHT BLUFFING")
  end


end

    receive_message(socket1)
    receive_message(socket2)
    start = receive_message(socket3)
    %{:turn => nil,
      :players => nil,
      :sockets => [socket1, socket2, socket3],
      :ports => [port1, port2, port3]}
    |> extract_player_seq(start)
  end

  defp check_broadcast_message(sockets, msg) do
    for s <- sockets do
      assert {:ok, {_ip, _port, ^msg}} = :gen_udp.recv(s, 0, @timeout)
    end
  end

  defp player_lost(game, playerno, reason) do
    check_broadcast_message(game[:sockets], "PLAYER LOST;#{game[:players][playerno][:name]};#{reason}\n")
    scoremsg = "SCORE;" <> (1..@players
      |> Enum.to_list
      |> Enum.map(fn n -> "#{game[:players][n][:name]}:#{if(n == playerno, do: 0, else: 1)}" end)
      |> Enum.sort()
      |> Enum.join(","))
    check_broadcast_message(game[:sockets], scoremsg <> "\n")
    invites = for s <- game[:sockets] do
      {:ok, {_ip, _port, invitation}} = :gen_udp.recv(s, 0, @timeout)
      invitation
    end
