package com.codingame.game;

import com.codingame.gameengine.core.AbstractPlayer.TimeoutException;
import com.codingame.gameengine.core.AbstractReferee;
import com.codingame.gameengine.core.MultiplayerGameManager;
import com.codingame.gameengine.module.endscreen.EndScreenModule;
import com.codingame.gameengine.module.entities.GraphicEntityModule;
import com.codingame.gameengine.module.tooltip.TooltipModule;
import com.codingame.gameengine.module.toggle.ToggleModule;
import com.google.inject.Inject;

import engine.*;
import view.*;

public class Referee extends AbstractReferee {

    @Inject private MultiplayerGameManager<Player> gameManager;
    @Inject private GraphicEntityModule graphicEntityModule;
    @Inject private TooltipModule tooltips;
    @Inject private ToggleModule toggleModule;
    @Inject private EndScreenModule endScreenModule;

    private Board     board;
    private BoardView view;
    private final int maxTurns = 350;

    @Override
    public void init() {
        // Initialize your game here.
        board = new Board(gameManager.getActivePlayers(), graphicEntityModule);
        view = new BoardView(board, graphicEntityModule, tooltips, toggleModule);
        gameManager.setMaxTurns(maxTurns);
        gameManager.setFirstTurnMaxTime(1000);
        gameManager.setTurnMaxTime(75);
    }

    @Override
    public void gameTurn(int turn) {

        Player currentPlayer = gameManager.getPlayer((turn + 2) % 2);
        boolean endGame = false;

        // send input
        board.sendInputToPlayer(currentPlayer, gameManager.getPlayer((turn + 1) % 2), turn <= 2);
        currentPlayer.execute();

        try {
            /*
                Output format:
                {First marble X} {First marble Y} {Last marble X} {Last marble Y} {Direction}

                Directions:
                   2 1
                  3 X 0
                   4 5
            */
            String[] outputs = currentPlayer.getOutputs().get(0).trim().split(" ");

            // bad number of outputs
            if (outputs.length != 5) {
                throw new Exception("");
            }

            int fX = Integer.parseInt(outputs[0]);
            int fY = Integer.parseInt(outputs[1]);
            int lX = Integer.parseInt(outputs[2]);
            int lY = Integer.parseInt(outputs[3]);
            int dir = Integer.parseInt(outputs[4]);
            
            int prev_score = currentPlayer.getScore();
            
            Move move = new Move(fX, fY, lX, lY, dir);
            endGame = board.applyMove(currentPlayer, move);

            if (prev_score != currentPlayer.getScore()) {
                gameManager.addTooltip(currentPlayer, "Scored point!");
            }
            
            view.updateBoard(board.getMoveLog());
        } catch (TimeoutException e) {
            currentPlayer.deactivate(String.format("Player $%d: timeout!", currentPlayer.getIndex()));
            currentPlayer.setScore(-1);
            endGame = true;
        } catch (NumberFormatException e) {
            currentPlayer.deactivate(String.format("Player $%d: invalid output!", currentPlayer.getIndex()));
            currentPlayer.setScore(-1);
            endGame = true;
        } catch (Exception e) {
            currentPlayer.deactivate(String.format("Player $%d: invalid action! " + e.getMessage(), currentPlayer.getIndex()));
            currentPlayer.setScore(-1);
            endGame = true;
        }

        // check turn limit
        if (turn == maxTurns) {
            endGame = true;
        }

        // game end
        if (endGame) {
            gameManager.endGame();
        }
    }

    @Override
    public void onEnd() {
        endScreenModule.setScores(gameManager.getPlayers().stream().mapToInt(p -> p.getScore()).toArray());
    }
}
