document.getElementById('startGame').addEventListener('click', function () {
    const gridSize = parseInt(document.getElementById('gridSize').value);
    const bombs = parseInt(document.getElementById('bombs').value);

    document.getElementById('settings').style.display = 'none';
    document.getElementById('game').style.display = 'block';

    renderGame(gridSize, bombs);
});

const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');

class Minesweeper {
    constructor(width, height, bombs) {
        this.size = 25;
        this.field = new Array(width);
        this.bombs = new Array(width);
        for (let x = 0; x < this.field.length; x++) {
            this.field[x] = new Array(height);
            this.bombs[x] = new Array(height);
            for (let y = 0; y < this.field[x].length; y++) {
                this.field[x][y] = 1;
                this.bombs[x][y] = false;
            }
        }

        this.bombAmount = bombs > width * height / 2 ? width * height / 2 : bombs;
        this.width = width;
        this.height = height;
        this.firstClick = false;
        this.drawField();
    }

    generateBombs() {
        for (let i = 0; i < this.bombAmount; i++) {
            let x = Math.floor(Math.random() * this.width);
            let y = Math.floor(Math.random() * this.height);
            (this.bombs[x][y] || this.field[x][y] == 0) ? i-- : this.bombs[x][y] = true;
        }
        this.firstClick = true;
    }

    getNearbyBombs(x, y) {
        let counter = 0;
        for (let newX = x - 1; newX <= x + 1; newX++) {
            for (let newY = y - 1; newY <= y + 1; newY++) {
                if (newX < this.field.length && newX >= 0 && newY < this.field[0].length && newY >= 0) {
                    this.bombs[newX][newY] ? counter++ : {};
                }
            }
        }
        return counter;
    }

    checkWin() {
        for (let x = 0; x < this.field.length; x++) {
            for (let y = 0; y < this.field[x].length; y++) {
                if (this.field[x][y] != 0 && !this.bombs[x][y]) {
                    return;
                } else if (this.field[x][y] == 0 && this.bombs[x][y]) {
                    alert(`[ERROR]: Square (${x}|${y}) should not be a bomb!`);
                    this.bombs[x][y] = false;
                }
            }
        }
        this.drawField();
        alert('You won!');
        window.location.reload();
    }

    markSquare(x, y) {
        if (x < this.field.length && y < this.field[0].length) {
            switch (this.field[x][y]) {
                case 1:
                    this.field[x][y]++;
                    break;
                case 2:
                    this.field[x][y]++;
                    break;
                case 3:
                    this.field[x][y] = 1;
                    break;
                default:
                    break;
            }
            this.drawField();
        }
    }

    uncoverSquare(x, y) {
        if (x < this.field.length && x >= 0 && y < this.field[0].length && y >= 0) {
            if (this.bombs[x][y] && this.field[x][y] == 1) {
                alert('You lost!');
                window.location.reload();
            } else if (this.field[x][y] == 1) {
                this.field[x][y] = 0;
                !this.firstClick ? this.generateBombs() : {};
                if (this.getNearbyBombs(x, y) == 0) {
                    for (let newX = x - 1; newX <= x + 1; newX++) {
                        for (let newY = y - 1; newY <= y + 1; newY++) {
                            if (newX < this.field.length && newX >= 0 && newY < this.field[0].length && newY >= 0) {
                                this.field[newX][newY] == 1 ? this.uncoverSquare(newX, newY) : {};
                            }
                        }
                    }
                }
            };
            this.checkWin();
            this.drawField();
        }
    }

    drawSquare(x, y, type) {
        ctx.lineWidth = 3;
        let uncovered = (x + y) % 2 === 0 ? '#D3D3D3' : '#A9A9A9';
        let covered = (x + y) % 2 === 0 ? '#4CAF50' : '#81C784';
        ctx.fillStyle = type != 0 ? covered : uncovered;
        ctx.fillRect(x * this.size, y * this.size, this.size, this.size);
        ctx.strokeStyle = '#000';
        ctx.strokeRect(x * this.size, y * this.size, this.size, this.size);

        if (type != 1) {
            const fontSize = this.size / 2;
            const number = this.getNearbyBombs(x, y);
            let finalPrint;
            ctx.font = `${fontSize}px sans-serif`;
            ctx.fillStyle = '#000';
            type == 0 ? finalPrint = number ? number : ' ' : {};
            type == 2 ? finalPrint = '🚩' : {};
            type == 3 ? finalPrint = '❓' : {};
            ctx.fillText(finalPrint, x * this.size + fontSize / (type == 0 ? 1.5 : 1.8), y * this.size + fontSize * 1.3);
        }
    }

    drawField() {
        if (window.innerWidth > window.innerHeight) {
            this.size = window.innerHeight / (this.field[0].length + 4);
        } else {
            this.size = window.innerWidth / (this.field.length + 4);
        }

        canvas.width = this.size * this.field.length;
        canvas.height = this.size * this.field[0].length;

        const offsetX = (canvas.width - (this.field.length * this.size)) / 2;
        const offsetY = (canvas.height - (this.field[0].length * this.size)) / 2;

        for (let x = 0; x < this.field.length; x++) {
            for (let y = 0; y < this.field[x].length; y++) {
                this.drawSquare(x, y, this.field[x][y], offsetX, offsetY);
            }
        }
    }
}

const renderGame = (gridSize, bombs) => {
    let field = new Minesweeper(gridSize, gridSize, bombs);
    window.addEventListener('resize', () => field.drawField());
    canvas.addEventListener('click', (event) => {
        const rect = canvas.getBoundingClientRect();
        const x = Math.floor((event.clientX - rect.left) / field.size);
        const y = Math.floor((event.clientY - rect.top) / field.size);
        field.uncoverSquare(x, y);
    });
    canvas.addEventListener('contextmenu', (event) => {
        event.preventDefault();
        const rect = canvas.getBoundingClientRect();
        const x = Math.floor((event.clientX - rect.left) / field.size);
        const y = Math.floor((event.clientY - rect.top) / field.size);
        field.markSquare(x, y);
    });
};
