import { Constants } from "./Constants.js";
import { elt } from "./elt.js";
import { State } from "./State.js";

/**
 * Represents a game.
 */
export class Game
{
    /**
     * The width of the board.
     */
    static #width = 7;

    /**
     * The height of the board.
     */
    static #height = 6;

    /**
     * The state of the game.
     *
     * @type {State}
     */
    #state;

    /**
     * The actual board.
     *
     * @type {HTMLElement}
     */
    #board;

    /**
     * The element containing a log message.
     *
     * @type {HTMLElement}
     */
    #log;

    /**
     * The id of the element to add the board to.
     *
     * @type {string}
     */
    id;

    /**
     * Initializes a new instance of the {@link Game `Game`} class.
     *
     * @param {string} id
     * The id of the element to add the board to.
     */
    constructor(id)
    {
        this.id = id;
        this.#state = new State(Game.#width, Game.#height);
    }

    /**
     * Gets the state of the game.
     */
    get state()
    {
        return this.#state;
    }

    /**
     * Gets the board of the game.
     */
    get board()
    {
        return this.state.board;
    }

    /**
     * Initializes the game.
     */
    initialize()
    {
        let container = document.getElementById(this.id);

        this.#board = elt(
            "div",
            {
                class: "board"
            });

        this.#log = elt(
            "div",
            {
                class: "log"
            });

        container.appendChild(this.#board);
        container.appendChild(this.#log);
        this.draw();
    }

    /**
     * Resets the game.
     */
    reset()
    {
        this.#state = new State(Game.#width, Game.#height);
        this.draw();
    }

    /**
     * Replaces the content of the board with the current state.
     */
    draw()
    {
        let board = this.#board;
        board.innerHTML = "";

        for (let y = 0; y < Game.#height; y++)
        {
            for (let x = 0; x < Game.#width; x++)
            {
                /** @type {Node[]} */
                let children = [];
                let playerId = this.board[y][x];

                if (playerId !== "")
                {
                    children.push(
                        elt(
                            "div",
                            {
                                class: `piece ${Constants.PLAYER_NAMES[playerId]}`
                            }));
                }

                let field = elt(
                    "div",
                    {
                        class: "field"
                    },
                    ...children);

                field.onclick = () =>
                {
                    if (this.addChip(x, y))
                    {
                        this.state.turnCount++;
                        this.draw();
                    }
                };

                board.appendChild(field);
            }
        }

        board.appendChild(
            elt(
                "div",
                {
                    style: "clear: both;"
                }));

        this.#log.className = "";
        this.#log.classList.add(this.state.currentPlayer);
        this.#log.innerHTML = "";
        this.#log.textContent = `It's player "${Constants.PLAYER_NAMES[this.state.currentPlayer]}"s turn`;
    }

    /**
     * Adds a chip to the board indicated by the {@link x `x`} and the {@link y `y`} coordinate.
     *
     * @param {number} x
     * The x coordinate to add the chip to.
     *
     * @param {number} y
     * The y coordinate to add the chip to.
     *
     * @returns {boolean}
     * A value indicating whether the chip could be added.
     */
    addChip(x, y)
    {
        for (let i = Game.#height - 1; i >= 0; i--)
        {
            if (this.board[i][x] === "")
            {
                this.board[i][x] = this.state.currentPlayer;
                return true;
            }
        }

        return false;
    }
}