// Récupération des variables en LocalStorage
const playerLogin = localStorage.getItem("login");
const gameID = localStorage.getItem("gameID");

const playerPrototype = {
	isA: function() { return (playerLogin==game.data.loginA) },
	isB: function() { return (playerLogin==game.data.loginB) },
	tag: function() { return (playerLogin==game.data.loginA)? 'A': 'B'},
	opponent: function() { return (playerLogin==game.data.loginA)? game.data.loginB: game.data.loginA },
	opponentTag: function() { return (playerLogin==game.data.loginA)? 'B': 'A' },
	myTurn: function() { return (game.data.playerTurn==this.tag()) },
	buyingCapacity: function() {
		const playerTokens = game.tokens.filter(token => token.slot==this.tag());
		const playerCards = game.cards.filter(card => card.slot==this.tag());
		var playerCardCapacity = {};
		var playerTokenCapacity = {};
		var playerBuyingCapacity = {};
		tokensColors.forEach(color => {
			const coloredCards = playerCards.filter(card => card.color==color);
			if(coloredCards) {
				playerCardCapacity[color] = coloredCards.reduce((somme, card) => {
					return somme+card.value;
				}, 0 ); 
			} else playerCardCapacity[color] = 0;
			playerTokenCapacity[color] = playerTokens.filter(token => token.color==color).length;
			playerBuyingCapacity[color] = playerCardCapacity[color]+playerTokenCapacity[color];
		});
		return {'global':playerBuyingCapacity, 'cards': playerCardCapacity, 'tokens': playerTokenCapacity};
	},
	score: function() {
		const playerCards = game.cards.filter(card => card.slot==this.tag());
		if(playerCards) {
			this.globalPrestige = playerCards.reduce((somme, card) => { return somme+card.prestige; }, 0);
			this.crowns = playerCards.reduce((somme, card) => { return somme+card.crown; }, 0);
			this.coloredPrestige = 0;
			cardsColors.forEach(color => {
				const coloredCards = playerCards.filter(card => card.color==color);
				if(coloredCards) {
					this.coloredPrestige = Math.max(this.coloredPrestige, coloredCards.reduce((somme, card) => { return somme+card.prestige; }, 0 )); 
				}
			});
			this.victory=(this.globalPrestige>=20 || this.crown>=10 || this.coloredPrestige>=10);
			return this.victory;
		} else return false;

	}
}

// Variables globales
const cardsColors = ['white', 'blue', 'green', 'red', 'black'];
const tokensColors = ['white', 'blue', 'green', 'red', 'black', 'pearl', 'gold'];

var tokenTransaction = Object.create(tokensPrototype);
var game = {};
var tkX; var tkY;

// Signaler la connexion du Joueur à Node
parent.nodeSend(playerLogin, 'In Game', {'gameID':gameID});

/* =========================================
		TRAITEMENT DES MESSAGES RECUS
	=========================================	*/
function messageProcessing(event) {
	trace(`> Réception données: ${event.data}`, 8);
	if(isJsonString(event.data)) {
		trace(' ... Message JSON valide', 10);
		const message = JSON.parse(event.data);
		const sender = message.from.toLowerCase();
		if(sender=='node') {
			const notification = message.notif;
			trace(`> Réception notification: ${notification} from ${sender}`, 2);
			switch(notification.toLowerCase()) {
				case 'add player':
					break;
				case 'remove player':
					break;
				case 'game data':
					game = message.data;
					// Ajouter les données spécifiques au client
					game.player = Object.create(playerPrototype);;

					Object.setPrototypeOf(game.tokens, tokensPrototype);
					game.tokens.forEach(token => {
						Object.setPrototypeOf(token, tokenPrototype);
						token.create(); token.display();
					});

					Object.setPrototypeOf(game.cards, cardsPrototype);
					game.cards.forEach(card => {
						Object.setPrototypeOf(card, cardPrototype);
						card.create(); card.display();
					});

					Object.setPrototypeOf(game.privileges, privilegesPrototype);
					game.privileges.forEach(privilege => {
						Object.setPrototypeOf(privilege, privilegePrototype);
						privilege.create(); privilege.display();
					});
					// AAfficher les info sur la partie en cours
					displayGameInfo();
					break;
				case('update data'):
					updateData(message.data);
					break;
				case 'player error':
					navWelcome();
					break;
				case 'game error':
					navWaitingRoom();
					break;
				case 'info':
					console.log(message.data);
					const snackbar = document.getElementById('snackbar');
					snackbar.textContent = message.data.msg;
					snackbar.classList.add('show');
					setTimeout(() => {snackbar.classList.remove('show');}, 3000);
					break;
				default:
					unknownMessage  = `!!! Réception d'un message inconnu)\n`;
					unknownMessage += ` Notification : ${notification}\n`;
					if(message.data) unknownMessage += ` Données : ${JSON.stringify(message.data)}`;
					console.error(unknownMessage);
			}
		}
	} else {
		console.error(`Message "${event.data}" non traité`);
	}
}

function updateData(data) {
	trace('Update data from Node', 1);
	if(data.gameData) {
		const gameData = data.gameData;
		trace(`... Update Game Data - gameData: ${JSON.stringify(gameData)}`);
		game.data = gameData;
		displayGameInfo();
	}
	if(data.cards) {
		trace(`... Update Cards - cards: ${JSON.stringify(data.cards)}`);
		data.cards.forEach(obj => {
			const card = game.cards.findByID(obj.cardID);
			if(obj.slot!=card.slot) card.moveToSlot(obj.slot);
		});
	}
	if(data.tokens) {
		trace(`... Update Tokens - tokens: ${JSON.stringify(data.tokens)}`);
		data.tokens.forEach(obj => {
			const token = game.tokens.findByID(obj.tokenID);
			if(obj.slot!=token.slot) token.moveToSlot(obj.slot);
		});
	}
	if(data.privileges) {
		trace(`... Update Privileges - privileges: ${JSON.stringify(data.privileges)}`);
		data.privileges.forEach(obj => {
			const privilege = game.privileges.findByID(obj.privilegeID);
			if(obj.slot!=privilege.slot) privilege.moveToSlot(obj.slot);
		});
	}
}

/* ===================================
		FONCTIONS COMMUNES
	=================================== */
function slotPlayerA(childrenID, grandchildID) {
	trace(`Search for playerA - child: #${childrenID} - grandchild: #${grandchildID}`, 7);
	if(game.player.isA()) return document.querySelector(`#myDeck #${childrenID} #${grandchildID}`);
	else return document.querySelector(`#opponentDeck #${childrenID} #${grandchildID}`);
}

function slotPlayerB(childrenID, grandchildID) {
	trace(`Search for playerB - child: #${childrenID} - grandchild: #${grandchildID}`, 7);
	if(game.player.isB()) return document.querySelector(`#myDeck #${childrenID} #${grandchildID}`);
	else return document.querySelector(`#opponentDeck #${childrenID} #${grandchildID}`);
}

function sendInfo(msg) {
	parent.nodeSend(playerLogin, 'info', {msg: `${playerLogin} ${msg}`, opponent: game.player.opponent()});
}
/* ===================================
		GESTION DU JEU
	=================================== */
function displayGameInfo() {
	trace(`Update game status `, 1)
	document.getElementById('gameID').textContent = `Partie #${game.data.id} - Tour : ${1+Math.trunc((game.data.round-1)/2)}${game.data.playerTurn} ${game.data.step}`;

	// Affichage des noms
	const loginA = document.getElementById('loginA');
	const loginB = document.getElementById('loginB');
	loginA.textContent = `${game.data.loginA}`;
	loginB.textContent = `${game.data.loginB}`;
	if(game.player.isA()) loginA.style.textDecoration = 'underline';	else loginB.style.textDecoration = 'underline';

	// Indicateur du tour de jeu
	const playerRound = document.getElementById('playerRound');
	if(game.player.myTurn()) playerRound.textContent='A toi de jouer'; else playerRound.textContent='';

	// Score du joueur
	game.player.score();
	if(game.player.globalPrestige>0) document.getElementById('globalPrestige').innerHTML='<span>'+game.player.globalPrestige+'</span>';
	if(game.player.crowns>0) document.getElementById('crowns').innerHTML='<span>'+game.player.crowns+'</span>';
	if(game.player.coloredPrestige>0) document.getElementById('coloredPrestige').innerHTML='<span>'+game.player.coloredPrestige+'</span>';

	// Masquage des commandes de jeu
	const options = document.getElementById('options');
	if(game.player.myTurn()) options.classList.remove('hidden'); else options.classList.add('hidden');

	if(game.data.status=='terminated') victory();
	else playerOptions();
}

function playerOptions() {
	// Désactivation systématique des commandes si une action est en cours (boutton annulation visible)
	const disableActions = !document.getElementById('cancelAction').classList.contains('hidden') || game.data.step=='standby';

	// Utiliser Privilège ? OUI si le Joueur à au moins un Privilège
	const privileges = game.privileges.filterBySlot(game.player.tag());
	trace(`Privilege owned by Player : ${privileges.length}`, 8);
	document.getElementById('usePrivilege').disabled = (privileges.length==0 || game.data.step=='mdt' || disableActions);

	// Recharge Jetons ? OUI s'il y a au moins un Jeton disponible
	const reserveToken = game.tokens.filter(token => token.slot=='');
	trace(`${reserveToken.length} token available in reserve`, 8);
	document.getElementById('reloadToken').disabled = (reserveToken.length==0 || game.data.step=='mdt' || disableActions);

	// Prendre des Jetons ? OUI s'il y a au moins un jeton (non OR) sur le plateau
	const availableToken = game.tokens.filter(token => token.slot=='C' && token.color!='gold');
	trace(`${availableToken.length} token on board for player (with dataset)`, 8);
	document.getElementById('pickToken').disabled = (!availableToken || disableActions);

	// Réserver un carte ? OUI s'il le Joueur à moins de 3 cartes en réserve et qu'il y a des Jeton Or disponibles
	const reservedCards = game.cards.filter(card => card.slot==`R${game.player.tag()}`);
	const nGoldenToken = game.tokens.filter(token => token.slot=='C' && token.color=='gold').length;
	trace(`Reserved Cards owned by Player : ${reservedCards.length}`, 8);
	document.getElementById('reserveCard').disabled = ((reservedCards.length==3 && nGoldenToken>0) || disableActions);

	// Acheter une carte ? ...
	document.getElementById('buyCard').disabled = (disableActions);
}

function endTurn() {
	trace('End turn', 1);
	// Controle des conditions de victoire
	game.player.score()

	// Mise à jour du tour de jeu
	if(game.data.status!='terminated') game.data.status = "active"
	game.data.playerTurn = (game.data.playerTurn=='A')? 'B' : 'A';
	game.data.step = 'gen';
	game.data.round++;

	trace('Game data sent from End Turn: ', 1);
	trace(game.data, 1);
	// Transmission des données de jeu à Node
	parent.nodeSend(playerLogin, 'Update Data', {'gameID':gameID, 'gameData':game.data});
	// Mise à jour du statut de jeu local
	displayGameInfo();
}

function enableCancelAction(fct) {
	const btnCancelAction = document.getElementById('cancelAction');
	// Affichage du bouton d'annulation
	btnCancelAction.classList.remove('hidden');
	btnCancelAction.setAttribute('onclick', fct);
	displayGameInfo();
}
function disableCancelAction() {
	const btnCancelAction = document.getElementById('cancelAction');
	// Masquage du bouton d'annulation
	btnCancelAction.classList.add('hidden');
	btnCancelAction.removeAttribute('onclick');
	displayGameInfo();
}

function restoreBoard() {
	const elmSelectable = document.querySelectorAll('.selectable');
	if(elmSelectable) elmSelectable.forEach(elm => {
		elm.classList.remove('selectable');
		elm.removeAttribute('onclick');
	});
	const elmUnselectable = document.querySelectorAll('.unselectable');
	if(elmUnselectable) elmUnselectable.forEach(elm => elm.classList.remove('unselectable'));
	const elmMark = document.querySelectorAll('.mark');
	if(elmMark) elmMark.forEach(elm => elm.classList.remove('mark'));

	document.getElementById('message').textContent = '';

	disableCancelAction();
	playerOptions();
}

function victory() {
	const divVictory = document.createElement('div');
	divVictory.classList.add('cover');
	if(game.player.victory) divVictory.innerHTML = '<p>Victoire</p>';
	else  divVictory.innerHTML = '<p>Vous avez perdu</p>';
	document.getElementById('z_innerview').appendChild(divVictory);
	sessionStorage.removeItem('page');
}

/* ===================================
		ACTIONS UTILISATEUR
	=================================== */
function usePrivilege() {
	trace(`Use a Privilege`, 1);
	// Affichage du bouton d'annulation
	enableCancelAction('restoreBoard()')
	// Autoriser la sélection d'un Jeton unique
	enableTokenSelection('one');
}

function reloadToken() {
	trace('Reload tokens', 1);
	tokenReload();
}

// Action du joueur
function pickToken() {
	trace('Pick token(s)', 1);
	// Affichage du bouton d'annulation
	enableCancelAction('restoreBoard()')
	// Autoriser la sélection d'un à trois tokens
	enableTokenSelection();
}

function reserveCard() {
	trace('Reserve a Card', 1);
	// Affichage du bouton d'annulation
	enableCancelAction('restoreBoard()')
	// Autorisation de sélection d'une carte (plateau et stack)
	enableCardReservation();
}

function buyCard() {
	trace('Buy a Card', 1);
	// Affichage du bouton d'annulation
	enableCancelAction('restoreBoard()')
	// Autorisation de sélection d'une carte (plateau et réserve "achetable")
	enableCardPurchase();
}

/* ==============================================================
		Gestion des compteurs de Jetons sur les Slots des Joueurs
	==============================================================	*/
// Sélectionnez tous les Slot de Jetons des Joueurs
const tokenPlayerSlotList = document.querySelectorAll('.tokenPlayerSlot');
// Configurez les options de l'observateur (quelles mutations observer)
var config = { childList: true};
// La fonction callback à exécuter lorsque des mutations sont observées
var callback = function(mutationsList, observer) {
	for(var mutation of mutationsList) {
   	if (mutation.type === 'childList') {
			const tokenAdded = Array.prototype.some.call(mutation.addedNodes, function(element) {return element.classList.contains('token');});
			const tokenRemoved = Array.prototype.some.call(mutation.removedNodes, function(element) {return element.classList.contains('token');});
			if(tokenAdded || tokenRemoved) {
				const nTokens = mutation.target.querySelectorAll('.token').length;
				trace('Slot:'+ mutation.target.parentNode.parentNode.id+' Color: '+mutation.target.id+' Token count: '+nTokens, 8);
				const divTag = mutation.target.querySelector('div.tag');
				if(nTokens>1) {
					if(divTag) {
						divTag.textContent=nTokens;
					} else {
						const divTag = document.createElement('div');
						divTag.classList.add('tag');
						divTag.setAttribute('z-index', '99');
						divTag.textContent=nTokens;
						mutation.target.appendChild(divTag);
						}
				} else {
					if(divTag) {
						mutation.target.removeChild(divTag);
					}
				}
			}
      }
	}
};
// Créez une instance de MutationObserver en lui passant la fonction de callback
var observer = new MutationObserver(callback);
// Commencez à observer le nœud cible avec les configurations spécifiées
tokenPlayerSlotList.forEach(element =>	observer.observe(element, config));
// Pour arrêter d'observer
// observer.disconnect();

