"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.matchSignal = exports.matchTerminate = exports.matchLoop = exports.matchLeave = exports.matchJoin = exports.matchJoinAttempt = exports.matchInit = void 0;
var types_1 = require("./types");
var MAX_PLAYERS = 4;
var GRID_SIZE = 100; // 10x10
var BOMB_COUNT = 30;
var ITEM_COUNT_MIN = 5;
var ITEM_COUNT_MAX = 10;
var matchInit = function (ctx, logger, nk, params) {
    logger.info('Match initialized');
    // Generate Grid
    var grid = Array(GRID_SIZE).fill(null).map(function () { return ({ type: 'empty', revealed: false }); });
    // Place Bombs
    var bombsPlaced = 0;
    while (bombsPlaced < BOMB_COUNT) {
        var idx = Math.floor(Math.random() * GRID_SIZE);
        if (grid[idx].type === 'empty') {
            grid[idx].type = 'bomb';
            bombsPlaced++;
        }
    }
    // Place Items
    var itemCount = Math.floor(Math.random() * (ITEM_COUNT_MAX - ITEM_COUNT_MIN + 1)) + ITEM_COUNT_MIN;
    var itemsPlaced = 0;
    while (itemsPlaced < itemCount) {
        var idx = Math.floor(Math.random() * GRID_SIZE);
        if (grid[idx].type === 'empty') {
            grid[idx].type = 'item';
            grid[idx].itemId = types_1.ItemTypes[Math.floor(Math.random() * types_1.ItemTypes.length)];
            itemsPlaced++;
        }
    }
    var state = {
        players: {},
        grid: grid,
        turnOrder: [],
        currentTurnIndex: 0,
        round: 1,
        winnerId: null,
        gameStarted: false
    };
    return {
        state: state,
        tickRate: 1, // 1 tick per second is enough for turn-based, but maybe higher for responsiveness
        label: 'Animal Minesweeper'
    };
};
exports.matchInit = matchInit;
var matchJoinAttempt = function (ctx, logger, nk, dispatcher, tick, state, presence, metadata) {
    if (state.gameStarted) {
        return { state: state, accept: false, rejectMessage: 'Game already started' };
    }
    if (Object.keys(state.players).length >= MAX_PLAYERS) {
        return { state: state, accept: false, rejectMessage: 'Match full' };
    }
    return { state: state, accept: true };
};
exports.matchJoinAttempt = matchJoinAttempt;
var matchJoin = function (ctx, logger, nk, dispatcher, tick, state, presences) {
    presences.forEach(function (presence) {
        // Random character assignment for now
        var character = types_1.CharacterTypes[Math.floor(Math.random() * types_1.CharacterTypes.length)];
        state.players[presence.userId] = {
            userId: presence.userId,
            sessionId: presence.sessionId,
            username: presence.username,
            avatar: '🦁', // Placeholder, map character to emoji later
            hp: 4, // Default HP
            maxHp: 4,
            status: [],
            character: character
        };
        state.turnOrder.push(presence.userId);
        logger.info("Player joined: ".concat(presence.userId));
    });
    // Check if full to start game
    // Fix: Use >= to handle potential race condition where multiple players join in same tick
    if (Object.keys(state.players).length >= MAX_PLAYERS && !state.gameStarted) {
        state.gameStarted = true;
        logger.info('Game Started! Broadcasting GAME_START');
        // Broadcast Game Start
        dispatcher.broadcastMessage(types_1.OpCode.GAME_START, JSON.stringify(state));
    }
    else {
        logger.info("Player joined. Count: ".concat(Object.keys(state.players).length, ". Broadcasting UPDATE_STATE"));
        // Broadcast updated state (new player joined)
        dispatcher.broadcastMessage(types_1.OpCode.UPDATE_STATE, JSON.stringify(state));
    }
    return { state: state };
};
exports.matchJoin = matchJoin;
var matchLeave = function (ctx, logger, nk, dispatcher, tick, state, presences) {
    presences.forEach(function (presence) {
        delete state.players[presence.userId];
        var idx = state.turnOrder.indexOf(presence.userId);
        if (idx > -1) {
            state.turnOrder.splice(idx, 1);
            // Adjust turn index if necessary
            if (idx < state.currentTurnIndex) {
                state.currentTurnIndex--;
            }
            if (state.currentTurnIndex >= state.turnOrder.length) {
                state.currentTurnIndex = 0;
            }
        }
    });
    // Broadcast updated state (player left)
    if (state.gameStarted && Object.keys(state.players).length > 0) {
        dispatcher.broadcastMessage(types_1.OpCode.UPDATE_STATE, JSON.stringify(state));
    }
    // If game in progress and players drop, handle logic (end game or continue)
    if (Object.keys(state.players).length < 2 && state.gameStarted) {
        state.winnerId = Object.keys(state.players)[0] || null;
        dispatcher.broadcastMessage(types_1.OpCode.GAME_OVER, JSON.stringify({ winnerId: state.winnerId }));
        return null; // End match
    }
    // Broadcast updated state (player left)
    if (state.gameStarted) {
        dispatcher.broadcastMessage(types_1.OpCode.UPDATE_STATE, JSON.stringify(state));
    }
    return { state: state };
};
exports.matchLeave = matchLeave;
var matchLoop = function (ctx, logger, nk, dispatcher, tick, state, messages) {
    if (!state.gameStarted)
        return { state: state };
    messages.forEach(function (message) {
        if (message.opCode === types_1.OpCode.MOVE) {
            var data = JSON.parse(nk.binaryToString(message.data));
            handleMove(state, message.sender.userId, data.index, logger, dispatcher);
        }
    });
    return { state: state };
};
exports.matchLoop = matchLoop;
var matchTerminate = function (ctx, logger, nk, dispatcher, tick, state, graceSeconds) {
    return { state: state };
};
exports.matchTerminate = matchTerminate;
var matchSignal = function (ctx, logger, nk, dispatcher, tick, state, data) {
    return { state: state, data: data };
};
exports.matchSignal = matchSignal;
// --- Helper Functions ---
function handleMove(state, userId, cellIndex, logger, dispatcher) {
    // Validate Turn
    var currentUserId = state.turnOrder[state.currentTurnIndex];
    if (userId !== currentUserId) {
        return; // Not your turn
    }
    var cell = state.grid[cellIndex];
    if (cell.revealed)
        return; // Already revealed
    // Reveal Cell
    cell.revealed = true;
    var player = state.players[userId];
    // Logic
    if (cell.type === 'bomb') {
        player.hp -= 2;
        // Check death...
    }
    else if (cell.type === 'item') {
        // Add item logic...
    }
    // Next Turn
    state.currentTurnIndex = (state.currentTurnIndex + 1) % state.turnOrder.length;
    // Broadcast Update
    dispatcher.broadcastMessage(types_1.OpCode.UPDATE_STATE, JSON.stringify(state));
}
