<template>
  <div>
    <div class="md-layout" v-if="error" @click="error = null">
      <div class="md-layout-item">
        <md-app>
          <md-app-content>
            Error: <br>
            {{ error }}
          </md-app-content>
        </md-app>
      </div>
    </div>
    <br>
    <div class="md-layout">
      <div class="md-layout-item">
        <md-app>
          <md-app-content>
            <md-field>
              <label>Name</label>
              <md-input v-model="name" :readonly="gameJoined"></md-input>
            </md-field>
            <md-field v-if="!gameStarted">
              <label>Game code</label>
              <md-input v-model="code" :readonly="gameJoined"></md-input>
            </md-field>
            <template v-if="!gameJoined">
              <md-button @click="createGame" class="md-raised">Create</md-button>
              <md-button @click="joinGame" class="md-raised">Join</md-button>
            </template>

            <template v-if="gameJoined && !gameStarted && owner">
              <md-button @click="startGame" class="md-raised md-primary">Start</md-button>
            </template>

            <template v-if="myTurn && !gameEnded">
              It is your turn, make a guess: <br>
              <md-field>
                <label>Dice count</label>
                <md-input type="number" v-model="diceCount"></md-input>
              </md-field>
              Die value: <br>
              <span v-for="n in 6" :key="'v'+n" @click="dieValue = n">
                <die :number="n" :selected="dieValue === n"></die>
              </span> <br><br>
              <md-button @click="makeGuess" class="md-raised md-primary">Guess</md-button>
              <md-button @click="callBluff" class="md-raised md-accent">Call</md-button>
            </template>
          </md-app-content>
        </md-app>
      </div>

      <div class="md-layout-item">
        <md-app>
          <md-app-content>
            <template v-if="gameJoined && !gameStarted">
              <span v-if="owner">Game created!</span>
              <span v-else>Game joined, now waiting or game to start</span>
              <br>
              PlayerId: {{ playerId }} <br>
              <template v-if="gameStateObject">
                Players: <br>
                <template v-for="player in gameStateObject.players">
                  - {{ player.name }}<br>
                </template>
                <br/>
                <game-rules-editor v-model="rules" :readonly="!owner"/>
              </template>
            </template>

            <template v-if="gameRunning">
              The game has started, lets go! <br>
            </template>

            <template v-if="gameStateObject && gameRunning">
              <span
                v-if="previousRound && previousRound.loser.hash === playerHash">You lost the previous round!<br></span>
              Round: {{ currentRound.number + 1 }} <br>
              Turn: {{ lastTurn ? lastTurn.number + 2 : 1 }} <br>

              Your throw: <br>
              <template v-for="(count, number) in currentRound.myRolls">
                <die v-for="n in count" :number="number" :key="'t'+n+number"></die>
              </template>
              <br><br>
              <template v-if="lastTurn">
                Last guesses: <br>
                <round-turns :round="currentRound"/>
              </template>
              <br>
              <template v-if="!myTurn">Someone else is playing, waiting for your turn<br></template>
              Players: <br>
              <template v-for="player in gameStateObject.players">
                -{{ player.hash === gameStateObject.currentPlayer.hash ? '>' : '-' }}{{ player.name }}<br>
              </template>
              <br>
            </template>

            <template v-if="gameEnded">
              The game is over, the winner is: {{ gameStateObject.currentPlayer.name }}<br>
            </template>
          </md-app-content>
        </md-app>
      </div>
    </div>
    <br>
    <template v-if="gameStateObject && gameStarted">
      History: <br>
      <template v-for="round in gameStateObject.rounds.slice().reverse()">
        <round :round="round" :players="playersKeyedById"/>
        <br>
      </template>
    </template>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import PerudoApi from "@/services/PerudoApi";
import Die from "@/components/Die.vue";
import {
  ApiObject,
  GameState,
  GameStateObject,
  IsStartedObject,
  JoinCreateGameObject,
  MyTurnObject,
  RoundObject,
  TurnObject,
  GameStateState,
  PlayerObject,
  GameRules
} from "@/objects/objects";
import Round from "@/components/Round.vue";
import RoundTurns from "@/components/RoundTurns.vue";
import GameRulesEditor from "@/components/GameRulesEditor.vue";

@Component({
  components: {GameRulesEditor, RoundTurns, Round, Die}
})
export default class Home extends Vue {
  private gameState: GameState = GameState.Setup;
  private gameStateObject: GameStateObject | null = null;
  private error: string | null = null;

  private name: string = process.env.VUE_APP_NAME;
  private code: string = '';
  private owner: boolean = false;

  private playerId: string | null = null;
  private playerHash: string | null = null;
  private gameTimer: number | null = null;

  private diceCount: string = '1';
  private dieValue: number = 2;

  private get gameJoined (): boolean {
    return this.gameState >= GameState.Joined;
  }

  private get gameStarted (): boolean {
    return this.gameState >= GameState.Started;
  }

  private get gameRunning (): boolean {
    return this.gameStarted && !this.gameEnded;
  }

  private get gameEnded (): boolean {
    return this.gameState === GameState.Ended;
  }

  private get myTurn (): boolean {
    return this.gameState === GameState.MyTurn;
  }

  private get playersKeyedById (): Record<string, PlayerObject> | undefined {
    let newPlayers: Record<string, PlayerObject> = {};
    if (this.gameStateObject) {
      let players = this.gameStateObject.players;
      for (let key in players) {
        newPlayers[players[key].hash] = players[key];
      }
    }
    return newPlayers;
  }

  private get previousRound (): RoundObject | undefined {
    let rounds = this.gameStateObject?.rounds;
    return rounds ? (rounds[rounds.length - 2] ?? undefined) : undefined;
  }

  private get currentRound (): RoundObject | undefined {
    let rounds = this.gameStateObject?.rounds;
    return rounds ? rounds[rounds.length - 1] : undefined;
  }

  private get lastTurn (): TurnObject | undefined {
    let turns = this.currentRound?.turns;
    return turns ? turns[turns.length - 1] : undefined;
  }

  private get rules (): GameRules | undefined {
    return this.gameStateObject?.rules;
  }

  private set rules (gameRules: GameRules | undefined) {
    console.log(gameRules);
    if (this.playerId && gameRules) {
      PerudoApi.instance.setGameRules(this.playerId, gameRules);
    }
  }

  private createGame (): void {
    if (this.name === '') {
      this.error = "Name cannot be empty";
      return;
    }
    PerudoApi.instance.createGame(this.name).then((response: JoinCreateGameObject) => {
      this.playerId = response.player.id;
      this.playerHash = response.player.hash;
      this.code = response.code;
      this.owner = true;

      this.gameState = GameState.Joined;
      this.gameTimer = setInterval(() => {
        this.checkStarted();
      }, 1000);
    }).catch((reason => {
      this.error = reason;
    }));
  }

  private joinGame (): void {
    if (this.code === '') {
      this.error = "Game code cannot be empty when joining a game";
      return;
    }
    if (this.name === '') {
      this.error = "Name cannot be empty";
      return;
    }
    PerudoApi.instance.joinGame(this.name, this.code).then((response: JoinCreateGameObject) => {
      this.playerId = response.player.id;
      this.playerHash = response.player.hash;
      this.gameTimer = setInterval(() => {
        this.checkStarted();
      }, 1000);

      this.gameState = GameState.Joined;
    }).catch((reason => {
      this.error = reason;
    }));
  }

  private startGame (): void {
    if (this.gameJoined && this.playerId) {
      PerudoApi.instance.startGame(this.playerId).then((response: ApiObject) => {
        this.gameState = GameState.Started;
        this.gameStateObject = null; // Bug fix because checkStarted gameStateObject misses some properties
        this.checkTurn();
      }).catch((reason => {
        this.error = reason;
      }));
    }
  }

  private makeGuess (): void {
    if (this.myTurn && this.playerId) {
      PerudoApi.instance.makeGuess(this.playerId, {
        diceCount: parseInt(this.diceCount),
        dieValue: this.dieValue,
      }).then((response: MyTurnObject) => {
        this.gameState = GameState.Started;
        this.gameTimer = setInterval(() => {
          this.checkTurn();
        }, 1000);
        this.checkTurn();
      }).catch((reason => {
        this.error = reason;
      }));
    }
  }

  private callBluff (): void {
    if (this.myTurn && this.playerId) {
      PerudoApi.instance.callBluff(this.playerId).then((response: MyTurnObject) => {
        this.gameState = GameState.Started;
        this.gameTimer = setInterval(() => {
          this.checkTurn();
        }, 1000);
        this.checkTurn();
      }).catch((reason => {
        this.error = reason;
      }));
    }
  }

  private checkStarted (): void {
    console.log("Check started");
    if (this.gameJoined && this.playerId) {
      PerudoApi.instance.gameStarted(this.playerId).then((response: IsStartedObject) => {
        this.gameStateObject = response.gameState;
        console.log(this.gameStateObject.rules);
        if (response.started) {
          this.gameState = GameState.Started;

          this.clearGameTimer();
          this.gameTimer = setInterval(() => {
            this.checkTurn();
          }, 1000);
        }
      }).catch((reason => {
        this.error = reason;
      }));
    }
  }

  private checkTurn (): void {
    console.log("Check turn");
    if (this.gameStarted && this.playerId) {
      PerudoApi.instance.myTurn(this.playerId).then((response: MyTurnObject) => {
        this.gameStateObject = response.gameState;
        if (this.gameStateObject.state === GameStateState.Ended) {
          this.gameState = GameState.Ended;
          this.clearGameTimer();
        }
        if (response.turn) {
          this.gameState = GameState.MyTurn;
          this.diceCount = this.lastTurn?.diceCount.toString() ?? this.diceCount;
          this.dieValue = this.lastTurn?.dieValue ?? this.dieValue;
          this.clearGameTimer();

          console.log(this.gameStateObject);
        }
      });
    }
  }

  private clearGameTimer (): void {
    if (this.gameTimer) {
      clearInterval(this.gameTimer);
      this.gameTimer = null;
    }
  }
}
</script>
