import { Player } from "./player.js";

// In standard Risk, this is 5
const _REINFORCEMENT_MULTIPLIER = 1;

const WAITING = 0;
const PRE_GAME = 1;
const PLAYING = 2;

export class Game {
    constructor() {
        this.us = null;
        this.players = {};
        this.state = WAITING;

        this.allPlaced = false;
    }

    isWaiting() {
        return this.state === WAITING;
    }

    isPregame() {
        return this.state === PRE_GAME;
    }

    isPlaying() {
        return this.state === PLAYING;
    }

    incrementState() {
        this.state += 1;

        const event = new CustomEvent("gameStateUpdate", {
            detail: { newState: this.state },
        });
        document.dispatchEvent(event);
    }

    playerCount() {
        return Object.values(this.players).length;
    }

    currentPlayer() {
        return Object.values(this.players).filter((p) => p.isPlaying)[0];
    }

    addPlayer(id, is_us, rsa_key, paillier_key) {
        let is_new = this.players[id] === undefined;

        if (this.isWaiting()) {
            this.players[id] = new Player(id, is_us, rsa_key, paillier_key);
            if (is_us) {
                this.us = this.players[id];
            }
        }

        if (is_new) {
            const event = new CustomEvent("addPlayer");
            document.dispatchEvent(event);
        }

        return is_new;
    }

    removePlayer(id) {
        if (this.players[id] !== undefined) {
            const event = new CustomEvent("removePlayer");
            document.dispatchEvent(event);
            delete this.players[id];
        }
    }

    keepAlive(id) {
        if (id !== this.us.id) {
            this.players[id].resetTimeout(this);
        }
    }

    setReady(id, ready) {
        this.players[id].ready = ready;

        const event = new CustomEvent("updatePlayer");
        document.dispatchEvent(event);

        if (this._allPlayersReady()) {
            this.incrementState();
        }
    }

    _allPlayersReady() {
        for (let player of Object.values(this.players)) {
            if (!player.ready) {
                return false;
            }
        }
        return true;
    }

    reinforcementsRemaining() {
        if (this.allPlaced) {
            return 0;
        } else {
            return (
                _REINFORCEMENT_MULTIPLIER * (10 - this.playerCount()) -
                this.us.totalStrength
            );
        }
    }

    allReinforcementsPlaced() {
        if (this.allPlaced) {
            return true;
        } else {
            let totalStrength = Object.values(this.players).reduce(
                (counter, player) => counter + player.totalStrength,
                0
            );

            this.allPlaced =
                totalStrength >=
                this.playerCount() *
                    _REINFORCEMENT_MULTIPLIER *
                    (10 - this.playerCount());
            return this.allPlaced;
        }
    }
}
