package xyz.jacobclark.integration.websockets;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import xyz.jacobclark.games.impl.Gomoku;

import java.lang.reflect.Type;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class GameControllerTest {
    static final String WEBSOCKET_URI = "ws://localhost:8080/ws";
    static final String WEBSOCKET_TOPIC_SUBSCRIPTION = "/topic/games/pieces";

    private BlockingQueue<String> blockingQueue;
    private WebSocketStompClient stompClient;

    @Before
    public void setup() {
        blockingQueue = new LinkedBlockingDeque<>();

        SockJsClient webSocketClient = new SockJsClient(asList(new WebSocketTransport(new StandardWebSocketClient())));
        stompClient = new WebSocketStompClient(webSocketClient);
    }

    @Test
    public void successfulPlacePieceCallToWebsocketPiecesEndpointReturnsAllCurrentPiecesOnBoard() throws Exception {
        ResponseEntity<Gomoku> response = new RestTemplate().postForEntity("http://localhost:8080/games", null, Gomoku.class);

        StompSession session = stompClient
                .connect(WEBSOCKET_URI, new StompSessionHandlerAdapter() {
                })
                .get(1, SECONDS);

        session.subscribe(WEBSOCKET_TOPIC_SUBSCRIPTION, new MockStompFrameHandler());

        String blackMovePayload = "{\"playerUuid\": \"" + response.getBody().getPlayers().get(0).getUuid().toString() + "\", \"column\": 0, \"row\": 0}";
        // TODO: Expose join game endpoint to join WHITE player to game
        //        String blackMovePayload = "{\"playerUuid\": \"" + response.getBody().getPlayers().get(0).getUuid().toString() + "\", \"column\": 0, \"row\": 0}";

        session.send("/app/games/" + response.getBody().getUuid() + "/pieces", blackMovePayload.getBytes());
        // TODO: Expose join game endpoint to join WHITE player to game
        //        session.send("/app/games/" + response.getBody().getUuid() + "/pieces", "{\"pebbleType\": \"WHITE\", \"column\": 0, \"row\": 1}".getBytes());

        String message = blockingQueue.poll(1, SECONDS);

        Assert.assertTrue(message.contains("{\"pebbleType\":\"BLACK\",\"column\":0,\"row\":0}"));
        // TODO: Expose join game endpoint to join WHITE player to game
        //        Assert.assertTrue(message.contains("{\"pebbleType\":\"WHITE\",\"column\":0,\"row\":1}"));
    }

    class MockStompFrameHandler implements StompFrameHandler {
        @Override
        public Type getPayloadType(StompHeaders stompHeaders) {
            return byte[].class;
        }

        @Override
        public void handleFrame(StompHeaders stompHeaders, Object o) {
            blockingQueue.offer(new String((byte[]) o));
        }
    }
}
@@ -974,16 +974,53 @@
 .Gomoku;
+%0Aimport xyz.jacobclark.models.Player;
 %0A%0Aimport
@@ -2247,16 +2247,196 @@
 .class);
+%0A        ResponseEntity%3CPlayer%3E joinGameResponse = new RestTemplate().postForEntity(%22http://localhost:8080/games/%22 + response.getBody().getUuid() + %22/players%22, null, Player.class);
 %0A%0A      
@@ -2846,90 +2846,8 @@
 %7D%22;%0A
-        // TODO: Expose join game endpoint to join WHITE player to game%0A        //
     
@@ -2849,37 +2849,37 @@
 %0A        String 
-black
+white
 MovePayload = %22%7B
@@ -2892,33 +2892,41 @@
 erUuid%5C%22: %5C%22%22 + 
-r
+joinGameR
 esponse.getBody(
@@ -2934,43 +2934,12 @@
 .get
-Players().get(0).getUuid().toString
+Uuid
 () +
@@ -2964,25 +2964,25 @@
 0, %5C%22row%5C%22: 
-0
+1
 %7D%22;%0A%0A       
@@ -3079,32 +3079,33 @@
 etBytes());%0A
+%0A
         
 // TODO: Exp
@@ -3096,82 +3096,28 @@
     
-// TODO: Expose join game endpoint to join WHITE player to game%0A        //
+Thread.sleep(100);%0A%0A
     
@@ -3195,78 +3195,96 @@
 s%22, 
-%22%7B%5C%22pebbleType%5C%22: %5C%22WHITE%5C%22, %5C%22column%5C%22: 0, %5C%22row%5C%22: 1%7D%22.getBytes());%0A
+whiteMovePayload.getBytes());%0A%0A        Thread.sleep(100);%0A%0A        blockingQueue.poll();
 %0A   
@@ -3324,26 +3324,16 @@
 ue.poll(
-1, SECONDS
 );%0A%0A    
@@ -3430,90 +3430,8 @@
 ));%0A
-        // TODO: Expose join game endpoint to join WHITE player to game%0A        //
     

Fix websocket integration test