package com.codingame.game;

import java.util.List;
import java.util.Random;

import com.codingame.game.engine.*;
import com.codingame.gameengine.core.AbstractPlayer.TimeoutException;
import com.codingame.gameengine.core.AbstractReferee;
import com.codingame.gameengine.core.SoloGameManager;
import com.codingame.gameengine.module.entities.*;
import com.codingame.gameengine.module.toggle.ToggleModule;
import com.codingame.gameengine.module.tooltip.TooltipModule;
import com.google.inject.Inject;


public class Referee extends AbstractReferee
{
  @Inject private SoloGameManager<Player> manager;
  @Inject private GraphicEntityModule graphic;
  @Inject private TooltipModule tooltip;
  @Inject private ToggleModule toggle;


  private Engine engine;
  private Viewer viewer;
  private Player player;

  private String[] playerMoves;




  @Override
  public void init()
  {
    engine = new Engine(manager);
    viewer = new Viewer(graphic);
    player = manager.getPlayer();

    viewer.init(engine, tooltip, toggle);
    //viewer.update(engine.state);

    manager.setFirstTurnMaxTime(20*1000);
    //manager.setTurnMaxTime(Constants.TIMELIMIT_TURN);
    manager.setMaxTurns(20);
    manager.setFrameDuration(1000);
    //player.expectedOutputLines = engine.solutionLength;
  }


  @Override
  public void gameTurn(int turn)
  {

    //GameState solution =  engine.BFS(engine.state);
    //System.out.println(solution);

    if (engine.state.mate)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showWinSummary();
      manager.winGame("PASSED!");
      return;
    }

    if (turn==1)
    {
      executePlayer();
      return;
    }

    applyMove(turn);

  }

  @Override
  public void onEnd()
  {
    //manager.putMetadata("Score", ""+gameState.score);
  }

  private boolean executePlayer()
  {
    try
    {
      manager.getPlayer().sendInputLine(engine.playerInput);
      manager.getPlayer().execute();
      playerMoves = manager.getPlayer().getOutputs().get(0).split("\\s+");
      //engine.validateAnswer(outputs);
    }
    //catch (InvalidActionException e)
    //{
    //  manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
    //  //viewer.showSummary(false);
    //  //manager.loseGame("[ERROR] "+e.getMessage());
    //  return false;
    //}
    catch (TimeoutException e)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showLoseSummary();
      manager.loseGame("[ERROR] Timeout!");
      return false;
    }
    catch (Exception e)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showLoseSummary();
      manager.loseGame(String.format("[ERROR] Output not properly formatted."));
      return false;
    }
    return true;
  }

  private void applyMove(int turn)
  {
    if (playerMoves.length < turn-1)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showLoseSummary();
      manager.loseGame(String.format("[ERROR] Expected more moves towards the checkmate. Valid solution requires %d moves.", engine.solutionLength));
      return;
    }

    if (turn-1 > engine.solutionLength)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showLoseSummary();
      manager.loseGame(String.format("[ERROR] Checkmate not executed in time. Valid solution requires %d moves.", engine.solutionLength));
      return;
    }

    String move = playerMoves[turn - 2];
    try
    {
      int actioncode = engine.validateAction(move);
      viewer.update(engine.state);
      engine.state = new GameState(engine.state, actioncode);
      viewer.showMove(engine.state);
    }
    catch (InvalidActionException e)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showLoseSummary();
      manager.loseGame("[ERROR] "+e.getMessage());
      return;
    }
    catch (Exception e)
    {
      manager.setFrameDuration(Constants.FRAMEDURATION_SUMMARY);
      viewer.showLoseSummary();
      manager.loseGame(String.format("[ERROR] Output not properly formatted. Each action should be in 'a1h8' format. Given '%s'.", move));
      return;
    }


  }
}
