package com.webcheckers.ui;

import com.webcheckers.appl.GameCenter;
import com.webcheckers.appl.GameLobby;
import com.webcheckers.model.PendingMoves;
import com.webcheckers.appl.PlayerLobby;
import com.webcheckers.model.Player;
import org.junit.Before;
import org.junit.Test;
import spark.*;
import spark.TemplateEngine;

import java.io.IOException;
import java.util.Map;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * testing class for PostSigninRoute
 * Created by Chres on 10/27/2017.
 */
public class PostSigninRouteTest {
    private PostSigninRoute CuT;

    private PlayerLobby playerLobby;
    private GameLobby gameLobby;
    private GameCenter gameCenter;

    private Request request;
    private Response response;
    private Session session;
    private TemplateEngine engine;


    @Before
    public void setup() {
        // set up mock objects
        request = mock(Request.class);
        session = mock(Session.class);
        when(request.session()).thenReturn(session);
        engine = mock(TemplateEngine.class);

        // set up friendly objects
        playerLobby = new PlayerLobby();
        playerLobby.addPlayer(new Player("inuse"));
        gameLobby = new GameLobby();
        gameCenter = new GameCenter(playerLobby, gameLobby);

        CuT = new PostSigninRoute(engine, gameCenter);
    }

    /**
     * testing for signing into the game with a player already in the game with the same name
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Test
    public void signinerrortest() throws IOException, ClassNotFoundException {
        // Arrange the test scenario: The session holds no player
        when(request.queryParams(PostSigninRoute.USERNAME_PARAM)).thenReturn("inuse");
        final Response response = mock(Response.class);


        //initiate testing environment
        final MyModelAndView myModelAndView = new MyModelAndView();
        when(engine.render(any(ModelAndView.class))).thenAnswer(MyModelAndView.makeAnswer(myModelAndView));

        // Invoke the test
        CuT.handle(request, response);

        // Analyze the results:
        // model is a non-null Map
        final Object model = myModelAndView.model;
        assertNotNull(model);
        assertTrue(model instanceof Map);
        // model contains all necessary View-Model data
        @SuppressWarnings("unchecked")
        final Map<String, Object> vm = (Map<String, Object>) model;

        //verify results
        assertEquals("You entered 'inuse' but the nickname is already in use." , vm.get(PostSigninRoute.MESSAGE_ATTR));
        // test view name
        assertEquals(PostSigninRoute.VIEW_NAME, myModelAndView.viewName);
    }

    /**
     * testing for signing into the game with an invalid player name
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Test
    public void signininvalidtest() throws IOException, ClassNotFoundException {
        // Arrange the test scenario: The session holds no player
        when(request.queryParams(PostSigninRoute.USERNAME_PARAM)).thenReturn("test\"");
        final Response response = mock(Response.class);


        //initiate testing environment
        final MyModelAndView myModelAndView = new MyModelAndView();
        when(engine.render(any(ModelAndView.class))).thenAnswer(MyModelAndView.makeAnswer(myModelAndView));

        // Invoke the test
        CuT.handle(request, response);

        // Analyze the results:
        // model is a non-null Map
        final Object model = myModelAndView.model;
        assertNotNull(model);
        assertTrue(model instanceof Map);
        // model contains all necessary View-Model data
        @SuppressWarnings("unchecked")
        final Map<String, Object> vm = (Map<String, Object>) model;

        //verify results
        assertEquals("You entered 'test\"', the nickname cannot contain the character \"." , vm.get(PostSigninRoute.MESSAGE_ATTR));
        // test view name
        assertEquals(PostSigninRoute.VIEW_NAME, myModelAndView.viewName);
    }


    /**
     * testing for signing into the game
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Test
    public void signintest() throws IOException, ClassNotFoundException {
        // Arrange the test scenario: The session holds no player
        when(request.queryParams(PostSigninRoute.USERNAME_PARAM)).thenReturn("test");
        final Response response = mock(Response.class);

        //initiate testing environment
        final MyModelAndView myModelAndView = new MyModelAndView();
        when(engine.render(any(ModelAndView.class))).thenAnswer(MyModelAndView.makeAnswer(myModelAndView));

        // Invoke the test
        CuT.handle(request, response);

        // Analyze the results:
        // model is a non-null Map
        final Object model = myModelAndView.model;
        assertNotNull(model);
        assertTrue(model instanceof Map);
        // model contains all necessary View-Model data
        @SuppressWarnings("unchecked")
        final Map<String, Object> vm = (Map<String, Object>) model;

        //verify results
        assertTrue(this.gameCenter.getPlayerLobby().hasPlayer(new Player("test")));
        assertEquals(new Player("test"), vm.get(GetGameRoute.CURRENT_PLAYER_ATTR));
        assertTrue(vm.get(GetHomeRoute.LOBBY_ATTR) instanceof String[]);
        assertEquals(this.gameCenter.getPlayerLobby().totalPlayers(), vm.get(GetHomeRoute.NUM_ATTR));
        assertNull(vm.get(PostSigninRoute.MESSAGE_ATTR));
        // test view name
        assertEquals(GetHomeRoute.VIEW_NAME, myModelAndView.viewName);
    }

}