package com.codingame.game.engine;


import com.codingame.gameengine.module.entities.*;
import com.codingame.gameengine.module.toggle.ToggleModule;
import com.codingame.gameengine.module.tooltip.TooltipModule;

import java.util.HashMap;
import java.util.Map;

public class Viewer
{
  private int BOARD_OFFSET_X = 600;
  private int BOARD_OFFSET_Y = 20;
  private int ACTION_MARGIN = 109/4; // 35;

  private double ACTION_ALPHA = 0.6;

  private int FONT_SIZE = 60;

  private Sprite whiteKing;
  private Sprite whiteRook;
  private Sprite blackKing;

  private HashMap<Integer, Sprite> blackKingActions = new HashMap<>();
  private HashMap<Integer, Sprite> whiteKingActions = new HashMap<>();
  private HashMap<Integer, Sprite> whiteRookActions = new HashMap<>();
  private Group actionsGroup;
  private Text[] HistoryListining;
  private Sprite whiteChar;
  private Sprite blackChar;

  private GraphicEntityModule graphic;
  private TooltipModule tooltip;
  private ToggleModule toggle;

  public Viewer(GraphicEntityModule graphic)
  {
    this.graphic = graphic;
  }


  public void init(Engine engine, TooltipModule tooltip, ToggleModule toggleModule)
  {
    this.tooltip = tooltip;
    this.toggle = toggleModule;

    actionsGroup = graphic.createGroup();
    actionsGroup.setZIndex(66);

    graphic.createSprite().setImage("background.png").setZIndex(0);
    graphic.createSprite().setImage("board.png").setZIndex(1).setX(BOARD_OFFSET_X).setY(BOARD_OFFSET_Y);
    graphic.createSprite().setImage("flag.png").setZIndex(2).setX(40).setY(BOARD_OFFSET_Y);

    whiteChar = graphic.createSprite().setImage("whiteChar.png").setZIndex(99).setScale(0.4).setX(1630).setY(760).setVisible(engine.state.whiteToMove);
    blackChar = graphic.createSprite().setImage("blackChar.png").setZIndex(99).setScale(0.4).setX(1630).setY(760).setVisible(!engine.state.whiteToMove);

    prepareCoordinates();

    blackKing = graphic.createSprite().setImage("blackKing.png").setZIndex(9).setX(getX(engine.state.blackKing)).setY(getY(engine.state.blackKing));
    whiteKing = graphic.createSprite().setImage("whiteKing.png").setZIndex(9).setX(getX(engine.state.whiteKing)).setY(getY(engine.state.whiteKing));
    whiteRook = graphic.createSprite().setImage("whiteRook.png").setZIndex(9).setX(getX(engine.state.whiteRook)).setY(getY(engine.state.whiteRook));

    tooltip.setTooltipText(blackKing, "Black King");
    tooltip.setTooltipText(whiteKing, "White King");
    tooltip.setTooltipText(whiteRook, "White Rook");

    prepareActionsVisualisers();
    toggle.displayOnToggleState(actionsGroup, "toggleLegalMoves", true);

    prepareHistoryListining(engine);


  }

  private void prepareCoordinates()
  {
    for (int y=0; y < 8; y++)
    {
      for (int x = 0; x < 8; x++)
      {
        Rectangle r = graphic.createRectangle().setZIndex(2).setAlpha(0.0).setX(BOARD_OFFSET_X + 78 + 109 * x)
                .setY(BOARD_OFFSET_Y + 78 + 109 * (7-y)).setWidth(109).setHeight(109);
        tooltip.setTooltipText(r, Constants.CoordinatesNumToStr(x*10+y));
      }
    }
  }

  private void prepareActionsVisualisers()
  {
    Sprite s;
    for (int y=0; y < 8; y++)
    {
      for (int x = 0; x < 8; x++)
      {
        //r = graphic.createRectangle().setZIndex(11).setFillColor(0x000000).setAlpha(0.0).setX(BOARD_OFFSET_X + 78 + 109 * x + ACTION_MARGIN).setY(BOARD_OFFSET_Y + 78 + 109 * (7-y) + ACTION_MARGIN).setWidth(109 - 2*ACTION_MARGIN).setHeight(109 - 2* ACTION_MARGIN);
        s = graphic.createSprite().setImage("blackKing.png").setZIndex(12).setScale(0.5).setAlpha(ACTION_ALPHA).setX(BOARD_OFFSET_X + 78 + 109 * x + ACTION_MARGIN).setY(BOARD_OFFSET_Y + 78 + 109 * (7-y) + ACTION_MARGIN).setVisible(false);
        blackKingActions.put(x*10+y, s);
        actionsGroup.add(s);
        //r = graphic.createRectangle().setZIndex(12).setFillColor(0xffffff).setAlpha(0.0).setX(BOARD_OFFSET_X + 78 + 109 * x + ACTION_MARGIN).setY(BOARD_OFFSET_Y + 78 + 109 * (7-y) + ACTION_MARGIN).setWidth(109 - 2*ACTION_MARGIN).setHeight(109 - 2* ACTION_MARGIN);
        s = graphic.createSprite().setImage("whiteKing.png").setZIndex(12).setScale(0.5).setAlpha(ACTION_ALPHA).setX(BOARD_OFFSET_X + 78 + 109 * x + ACTION_MARGIN).setY(BOARD_OFFSET_Y + 78 + 109 * (7-y) + ACTION_MARGIN).setVisible(false);
        whiteKingActions.put(x*10+y, s);
        actionsGroup.add(s);
        //r = graphic.createRectangle().setZIndex(13).setFillColor(0xffffff).setAlpha(0.0).setX(BOARD_OFFSET_X + 78 + 109 * x + ACTION_MARGIN).setY(BOARD_OFFSET_Y + 78 + 109 * (7-y) + ACTION_MARGIN).setWidth(109 - 2*ACTION_MARGIN).setHeight(109 - 2* ACTION_MARGIN);
        s = graphic.createSprite().setImage("whiteRook.png").setZIndex(13).setScale(0.5).setAlpha(ACTION_ALPHA).setX(BOARD_OFFSET_X + 78 + 109 * x + ACTION_MARGIN).setY(BOARD_OFFSET_Y + 78 + 109 * (7-y) + ACTION_MARGIN).setVisible(false);
        whiteRookActions.put(x*10+y, s);
        actionsGroup.add(s);
      }
    }
  }

  private void prepareHistoryListining(Engine engine)
  {
    // https://en.wikipedia.org/wiki/Pawnless_chess_endgame#Tables // max depth is 16
    // http://www.gilith.com/chess/endgames/kr_k.html
    HistoryListining = new Text[engine.solutionLength];
    for (int i=0; i < engine.solutionLength; i++)
      HistoryListining[i] = graphic.createText(String.format("%2d.",(i+1))).setZIndex(3).setX(120).setY(BOARD_OFFSET_Y+40+FONT_SIZE*i).setFontSize(FONT_SIZE).setAnchor(0.0).setFillColor(0x000000).setAlpha(1);
      //HistoryListining[i]= graphic.createText((i+1)+". ♖ a1-d1+").setZIndex(3).setX(120).setY(BOARD_OFFSET_Y+40+FONT_SIZE*i).setFontSize(FONT_SIZE).setAnchor(0.0).setFillColor(0x000000).setAlpha(1);


    //Text t = graphic.createText("1. ♔ a2-b2").setZIndex(3).setX(100).setY(BOARD_OFFSET_Y+FONT_SIZE*0).setFontSize(FONT_SIZE).setAnchor(0.0).setFillColor(0x000000).setAlpha(1);
    //Text r = graphic.createText("2. ♚ d2-d3").setZIndex(3).setX(100).setY(BOARD_OFFSET_Y+FONT_SIZE*1).setFontSize(FONT_SIZE).setAnchor(0.0).setFillColor(0x000000).setAlpha(1);
    //Text s = graphic.createText("3. ♖ a1-d1").setZIndex(3).setX(100).setY(BOARD_OFFSET_Y+FONT_SIZE*2).setFontSize(FONT_SIZE).setAnchor(0.0).setFillColor(0x000000).setAlpha(1);
    //Text a = graphic.createText("4. ♚ d3-d1").setZIndex(3).setX(100).setY(BOARD_OFFSET_Y+FONT_SIZE*3).setFontSize(FONT_SIZE).setAnchor(0.0).setFillColor(0x000000).setAlpha(1);


  }

  public void update(GameState state)
  {
    for (Map.Entry<Integer, Sprite> pair: blackKingActions.entrySet())
    {
      pair.getValue().setVisible(state.blackKingAction.contains(pair.getKey()) && !state.whiteToMove);
    }
    for (Map.Entry<Integer, Sprite> pair: whiteKingActions.entrySet())
    {
      pair.getValue().setVisible(state.whiteKingAction.contains(pair.getKey()) && state.whiteToMove);
    }
    for (Map.Entry<Integer, Sprite> pair: whiteRookActions.entrySet())
    {
      pair.getValue().setVisible(state.whiteRookAction.contains(pair.getKey()) && state.whiteToMove);
    }

    whiteChar.setVisible(state.whiteToMove);
    blackChar.setVisible(!state.whiteToMove);

    graphic.commitWorldState(0);
  }

  public void showMove(GameState state)
  {
    HistoryListining[state.depth-1].setText(String.format("%2d. %s", state.depth, String.join("", state.actionShow)));

    graphic.commitWorldState(0);

    if (state.action/100==1) whiteRook.setX(getX(state.whiteRook)).setY(getY(state.whiteRook));
    if (state.action/100==2) whiteKing.setX(getX(state.whiteKing)).setY(getY(state.whiteKing));
    if (state.action/100==3) blackKing.setX(getX(state.blackKing)).setY(getY(state.blackKing));

    if (state.whiteRook==-1) whiteRook.setVisible(false);

    graphic.commitWorldState(1);
  }

  public void showWinSummary() // https://cooltext.com/Logo-Design-Spring LOGO: #ECEA4B #8D570F 7, 2
  {
    actionsGroup.setVisible(false);
    whiteChar.setVisible(false);
    blackChar.setVisible(false);

    Sprite end = graphic.createSprite().setImage("passed.png").setX(960).setY(540).setAlpha(1).setAnchor(0.5).setScale(2.5).setZIndex(666);
    Sprite crown = graphic.createSprite().setImage("crown.png").setX(960).setY(340).setAlpha(1).setAnchor(0.5).setScale(2.5).setZIndex(666);
    graphic.commitWorldState(0);

    whiteChar.setVisible(true);
    whiteChar.setX(2000).setY(800).setAnchor(0.5);
    blackChar.setVisible(true);
    blackChar.setScaleX(-0.4);
    blackChar.setX(-80).setY(800).setAnchor(0.5);

    graphic.commitWorldState(0);
    for (int i=0; i < 10; i++)
    {
      whiteChar.setY(750 + (i%2)*50).setX(2000 - (i+1)*90);
      blackChar.setY(750 + (i%2)*50).setX(-80 + (i+1)*90);
      graphic.commitWorldState(0.09*i);
    }
  }

  public void showLoseSummary()
  {
    actionsGroup.setVisible(false);
    whiteChar.setVisible(false);
    blackChar.setVisible(false);

    Sprite end = graphic.createSprite().setImage("failed.png").setX(1010).setY(540).setAlpha(1).setAnchor(0.5).setScale(2.5).setZIndex(666);
    Sprite redChar = graphic.createSprite().setImage("redChar.png").setZIndex(99).setScale(0.4).setX(1010).setY(-50).setAnchor(0.5);
    graphic.commitWorldState(0);

    redChar.setY(900);
    graphic.commitWorldState(0.4);
    redChar.setY(800);
    graphic.commitWorldState(0.6);
    redChar.setY(850);
    graphic.commitWorldState(0.7);
    redChar.setY(800);
    graphic.commitWorldState(0.8);
  }

  private int getX(int position)
  {
    return BOARD_OFFSET_X + 78 + 109 * (position / 10);
  }

  private int getY(int position)
  {
    return BOARD_OFFSET_Y + 78 + 109 * (7 - position % 10);
  }
}
