const mongoose = require('mongoose');
const { COLORS, MOVE_TIME } = require('../utils/constants');
const { makeRandomMove } = require('../handlers/handlersFunctions');
const timeoutManager = require('./timeoutManager.js');
const PawnSchema = require('./pawn');
const PlayerSchema = require('./player');

// Safe/colored box positions in Ludo (where pawns cannot be killed)
const SAFE_POSITIONS = [16, 29, 42, 55];
// const HOME_ENTRY_POSITIONS = [66, 27, 40, 53];
const STAR_POSITIONS = [63, 24, 37, 50];

const isSafePosition = (position) => {
    return SAFE_POSITIONS.includes(position)
    || STAR_POSITIONS.includes(position) 
    || position > 66; // Also safe in home stretch
};

const RoomSchema = new mongoose.Schema({
    name: String,
    private: { type: Boolean, default: false },
    password: String,
    createDate: { type: Date, default: Date.now },
    started: { type: Boolean, default: false },
    full: { type: Boolean, default: false },
    nextMoveTime: Number,
    rolledNumber: Number,
    players: [PlayerSchema],
    winner: { type: String, default: null },
    pawns: {
        type: [PawnSchema],
        default: () => {
            const startPositions = [];
            for (let i = 0; i < 16; i++) {
                let pawn = {};
                pawn.basePos = i;
                pawn.position = i;
                if (i < 4) pawn.color = COLORS[0];
                else if (i < 8) pawn.color = COLORS[1];
                else if (i < 12) pawn.color = COLORS[2];
                else if (i < 16) pawn.color = COLORS[3];
                startPositions.push(pawn);
            }
            return startPositions;
        },
    },
});

RoomSchema.methods.beatPawns = function (position, attackingPawnColor) {
    // Do not beat pawns on safe/colored positions
    if (isSafePosition(position)) {
        return 0;
    }
    let beatenCount = 0;
    const pawnsOnPosition = this.pawns.filter(pawn => pawn.position === position);
    pawnsOnPosition.forEach(pawn => {
        if (pawn.color !== attackingPawnColor) {
            const index = this.getPawnIndex(pawn._id);
            if (index !== -1 && this.pawns[index].position !== this.pawns[index].basePos) {
                this.pawns[index].position = this.pawns[index].basePos;
                beatenCount++;
            }
        }
    });
    return beatenCount;
};

RoomSchema.methods.changeMovingPlayer = function () {
    if (this.winner) return;
    if (!Array.isArray(this.players) || this.players.length === 0) {
        console.warn(`[room:${this._id}] changeMovingPlayer: players array is empty or null`);
        return;
    }
    const playerIndex = this.players.findIndex(player => player && player.nowMoving === true);
    if (playerIndex === -1) {
        console.warn(`[room:${this._id}] changeMovingPlayer: no player currently marked as nowMoving`);
        // Default to first player
        this.players[0].nowMoving = true;
    } else {
        this.players[playerIndex].nowMoving = false;
        if (playerIndex + 1 === this.players.length) {
            this.players[0].nowMoving = true;
        } else {
            this.players[playerIndex + 1].nowMoving = true;
        }
    }
    this.nextMoveTime = Date.now() + MOVE_TIME;
    this.rolledNumber = null;
    timeoutManager.clear(this._id.toString());
    timeoutManager.set(makeRandomMove, MOVE_TIME, this._id.toString());
};

RoomSchema.methods.resetTurnForSamePlayer = function () {
    if (this.winner) return;
    // Keep the same player moving but reset the roll and move timer
    const now = Date.now();
    const currentPlayer = this.getCurrentlyMovingPlayer();
    if (!currentPlayer) {
        console.warn(`[room:${this._id}] resetTurnForSamePlayer: No current player found!`);
        return;
    }
    this.nextMoveTime = now + MOVE_TIME;
    this.rolledNumber = null;
    console.log(`[room:${this._id}] resetTurnForSamePlayer: player=${currentPlayer.color}, now=${now}, nextMoveTime=${this.nextMoveTime}, MOVE_TIME=${MOVE_TIME}`);
    timeoutManager.clear(this._id.toString());
    timeoutManager.set(makeRandomMove, MOVE_TIME, this._id.toString());
};

RoomSchema.methods.movePawn = function (pawn) {
    const newPositionOfMovedPawn = pawn.getPositionAfterMove(this.rolledNumber);
    this.changePositionOfPawn(pawn, newPositionOfMovedPawn);
    this.beatPawns(newPositionOfMovedPawn, pawn.color);
};

RoomSchema.methods.getPawnsThatCanMove = function () {
    const movingPlayer = this.getCurrentlyMovingPlayer();
    if (!movingPlayer) return [];
    const playerPawns = this.getPlayerPawns(movingPlayer.color);
    return (playerPawns || []).filter(pawn => pawn.canMove(this.rolledNumber));
};

RoomSchema.methods.changePositionOfPawn = function (pawn, newPosition) {
    const pawnIndex = this.getPawnIndex(pawn._id);
    this.pawns[pawnIndex].position = newPosition;
};

RoomSchema.methods.canStartGame = function () {
    if (!Array.isArray(this.players)) return false;
    return this.players.filter(player => player && player.ready).length >= 2;
};

RoomSchema.methods.startGame = function () {
    if (!Array.isArray(this.players) || this.players.length === 0) {
        console.warn(`[room:${this._id}] startGame: players array empty`);
        return;
    }
    this.started = true;
    this.nextMoveTime = Date.now() + MOVE_TIME;
    this.players.forEach(player => (player.ready = true));
    this.players[0].nowMoving = true;
    timeoutManager.set(makeRandomMove, MOVE_TIME, this._id.toString());
};

RoomSchema.methods.endGame = function (winner) {
    timeoutManager.clear(this._id.toString());
    this.rolledNumber = null;
    this.nextMoveTime = null;
    if (Array.isArray(this.players)) this.players.forEach(player => (player.nowMoving = false));
    this.winner = winner;
    this.save();
};

RoomSchema.methods.getWinner = function () {
    if (!Array.isArray(this.pawns)) return null;
    if (this.pawns.filter(pawn => pawn && pawn.color === 'red' && pawn.position === 73).length === 4) {
        return 'red';
    }
    if (this.pawns.filter(pawn => pawn && pawn.color === 'blue' && pawn.position === 79).length === 4) {
        return 'blue';
    }
    if (this.pawns.filter(pawn => pawn && pawn.color === 'green' && pawn.position === 85).length === 4) {
        return 'green';
    }
    if (this.pawns.filter(pawn => pawn && pawn.color === 'yellow' && pawn.position === 91).length === 4) {
        return 'yellow';
    }
    return null;
};

RoomSchema.methods.isFull = function () {
    if (!Array.isArray(this.players)) return false;
    if (this.players.length === 4) {
        this.full = true;
    }
    return this.full;
};

RoomSchema.methods.getPlayer = function (playerId) {
    if (!Array.isArray(this.players)) return null;
    return this.players.find(player => player && player._id && player._id.toString() === playerId.toString()) || null;
};

RoomSchema.methods.addPlayer = function (name, id) {
    if (this.full) return;
    if (!Array.isArray(this.players)) this.players = [];
    this.players.push({
        sessionID: id,
        name: name,
        ready: false,
        color: COLORS[this.players.length],
    });
};

RoomSchema.methods.getPawnIndex = function (pawnId) {
    if (!Array.isArray(this.pawns)) return -1;
    return this.pawns.findIndex(pawn => pawn && pawn._id && pawn._id.toString() === pawnId.toString());
};

RoomSchema.methods.getPawn = function (pawnId) {
    if (!Array.isArray(this.pawns)) return null;
    return this.pawns.find(pawn => pawn && pawn._id && pawn._id.toString() === pawnId.toString()) || null;
};

RoomSchema.methods.getPlayerPawns = function (color) {
    if (!Array.isArray(this.pawns)) return [];
    return this.pawns.filter(pawn => pawn && pawn.color === color);
};

RoomSchema.methods.getPawnsOnPosition = function (position) {
    if (!Array.isArray(this.pawns)) return [];
    return this.pawns.filter(pawn => pawn && pawn.position === position);
};

RoomSchema.methods.isStacked = function (position) {
    return this.getPawnsOnPosition(position).length > 1;
};

RoomSchema.methods.getOpponentPawnsOnPosition = function (position, color) {
    return this.getPawnsOnPosition(position).filter(pawn => pawn.color !== color);
};

RoomSchema.methods.getCurrentlyMovingPlayer = function () {
    if (!Array.isArray(this.players)) return null;
    return this.players.find(player => player && player.nowMoving === true) || null;
};

const Room = mongoose.model('Room', RoomSchema);

module.exports = Room;
