// Import des modules nécessaires
const WebSocketServer = require('ws');
const crypto = require('crypto');
const mariadb = require('mariadb');
const moment = require('moment');


// Déclaration des variables globales
const nodeID	= 'NODE';
const rootDir	= __dirname.substring(0, __dirname.lastIndexOf("\\"));

// Création de la connexion à la base MariaDB
const pool = mariadb.createPool({
	host: 'localhost',
	port: 3306,
	user:'splendor', 
	password: '7uj5ktja',
	database: 'splendor'
});

 
 /* ===============================================================
		PROCEDURES DIVERSES
	===============================================================	*/
// Test si une chaine est interprétable en tant que JSON
function isJsonString(str) {
	try {
		JSON.parse(str);
	} catch (e) {
		return false;
	}
	return true;
}

function trace(msg, error=false) {
	let datenow = new Date().toLocaleDateString();
	let heurenow = new Date().toLocaleTimeString();
	let now = datenow+' '+heurenow;
	if(!error) {
		console.log(now+' : '+msg);
	} else {
		console.error(now+' : '+msg);
	}
}

function schuffle(tab) {
	var i, j, tmp;
	for (i = tab.length - 1; i > 0; i--) {
		 j = Math.floor(Math.random() * (i + 1));
		 tmp = tab[i];
		 tab[i] = tab[j];
		 tab[j] = tmp;
	}
	return tab;
}

/* ===============================================================
		GESTION REQUETES SQL
	===============================================================	*/
// Exécution d'une requête générique
async function sqlQuery(query) {
	let cnxDB;
	try {
   	cnxDB = await pool.getConnection();
		trace(' ... SQL : '+query);
   	const rows = await cnxDB.query(query);
		//trace(rows);
		return rows;
	} catch (err) {
		console.log(err);
   	throw err;
	} finally {
   	if(cnxDB) cnxDB.release(); // Libère la connexion
	}
}

// Requête de d'insertion 
async function sqlInsert(table, data) {
	let cnxDB;
	try {
		cnxDB = await pool.getConnection(); 
		const champs = Object.keys(data).join(',');
		const valeurs = Object.values(data).map(val => cnxDB.escape(val)).join(',');
		const query = `INSERT INTO ${table} (${champs}) VALUES (${valeurs})`;
		trace(` ... SQL : ${query}`);
		const result = await cnxDB.query(`INSERT INTO ${table} (${champs}) VALUES (${valeurs})`);
		trace(result);
		return parseInt(result.insertId, 10);
	} catch (err) {
		console.log(err);
		throw err;
	} finally {
		if(cnxDB) cnxDB.release(); // Libère la connexion
	}
}
 
 // Requête d'Update
 async function sqlUpdate(table, data, filter) {
	let cnxDB;
	try {
		cnxDB = await pool.getConnection();
		// Création de l'ensemble des tuples à modifier
		var values = '';
		for(const field in data){
			if(data.hasOwnProperty(field)) {
				values += `${field}=`+cnxDB.escape(data[field])+`, `;
			}
		}
		// Suppression de la dernière virgule
		values = values.slice(0, -2);
 		const query = `UPDATE ${table} SET ${values} WHERE ${filter}`
		trace(` ... SQL : ${query}`);
		await cnxDB.query(query);
		return true
	} catch (err) {
		console.log(err);
		throw err;
	} finally {
		if (cnxDB) cnxDB.release(); // Libère la connexion
	}
 }

 /* ===============================================================
		
	===============================================================	*/
	async function initGame(playerA_ID, playerB_ID) {
		trace('Initialize or retreive game', 1);
		const games = await sqlQuery(`SELECT * FROM game WHERE status<>'terminated' AND (playerA_ID=${playerA_ID} AND playerB_ID=${playerB_ID}) OR (playerA_ID=${playerB_ID} AND playerB_ID=${playerA_ID})`)
		if(games.length>0) {
			trace(`gameID#${games[0]} retreived`, 1);
			return games[0].id;
		}
	
		// Tirage au sort du joueur
		const playerTurn = (Math.random()<0.5)? 'A' : 'B';
		const opponentSlot = (playerTurn==='A')? 'B' : 'A';
		//Création de la partie
		//const gameID = await sqlInsert('game', {'dateTime':moment().format('YYYY-MM-DD hh:mm:ss'), 'playerA_ID':playerA_ID, 'playerB_ID':playerB_ID, 'status':'init', 'round':1, 'step':'', 'playerTurn':playerTurn});
		// Chargement des caractéristiques des Cartes
		const cards = await sqlQuery('SELECT * FROM card');
		nDrawnCards = 5;
		const cardsL1 = schuffle(cards.filter(card => card.level==1));
		var rank = 0; cardsL1.forEach(card => card.rank = ++rank );
		for(let i=1; i<=nDrawnCards; i++) {
			cardsL1[cardsL1.length-i].slot = 'X';
			cardsL1[cardsL1.length-i].rank = i;
		}
		nDrawnCards--;
		const cardsL2 = schuffle(cards.filter(card => card.level==2));
		var rank = 0; cardsL2.forEach(card => card.rank = ++rank );
		for(let i=1; i<=nDrawnCards; i++) {
			cardsL1[cardsL2.length-i].slot = 'Y';
			cardsL1[cardsL2.length-i].rank = i;
		}
		nDrawnCards--;
		const cardsL3 = schuffle(cards.filter(card => card.level==3));
		var rank = 0; cardsL3.forEach(card => card.rank = ++rank );
		for(let i=1; i<=nDrawnCards; i++) {
			cardsL1[cardsL3.length-i].slot = '7';
			cardsL1[cardsL3.length-i].rank = i;
		}
		nDrawnCards--;

		//console.log(cards);

		/*
		// Création et mélange des cartes N1
		random = getRandomSeries(30);
		for(let i=0;  i<=29; i++) {
			var cardID = i+1;
			var card = cards.find(card => card.id===cardID)
			await sqlInsert('g_card', {'gameID':gameID, 'cardID':cardID  , 'slot':'', 'rank':random[i], 'color':card.initColor});
		}
		// Tirage des 5 cartes retournées
		for(let i=1; i<=5; i++) await drawCard(gameID, 1, 'X', i);
	
		// Création et mélange des cartes N2
		random = getRandomSeries(24);
		for(let i=0;  i<=23; i++) {
			var cardID = i+40;
			var card = cards.find(card => card.id===cardID)
			await sqlInsert('g_card', {'gameID':gameID, 'cardID':cardID , 'slot':'', 'rank':random[i], 'color':card.initColor});
		}
		// Tirage des 4 cartes retournées
		for(let i=1; i<=4; i++) await drawCard(gameID, 2, 'Y', i);
	
		// Création et mélange des cartes N3
		random = getRandomSeries(13);
		for(let i=1;  i<=12; i++) {
			var cardID = i+70;
			var card = cards.find(card => card.id===cardID)
			await sqlInsert('g_card', {'gameID':gameID, 'cardID':cardID , 'slot':'', 'rank':random[i], 'color':card.initColor})
		}
		// Tirage des 3 cartes retournées
		for(let i=1; i<=3; i++) await drawCard(gameID, 3, 'Z', i);
		
		// Création des cartes Royales
		for(let i=1;  i<=4; i++) {
			var cardID = i+100;
			await sqlInsert('g_card', {'gameID':gameID, 'cardID':cardID , 'slot':'R', 'rank':i, 'color':'neutral'});
		}
		
		// Création et mélange des jetons (positionné directement sur le plateau 'P')
		random = getRandomSeries(25);
		for(let i=0;  i<=24; i++) await sqlInsert('g_token', {'gameID':gameID, 'tokenID':i+1  , 'slot':'C', 'rank':random[i]});
	
		// Création des Privileges
		await sqlInsert('g_privilege', {'gameID':gameID, 'privilegeID':1, 'slot':'P', 'rank':1});
		await sqlInsert('g_privilege', {'gameID':gameID, 'privilegeID':2, 'slot':'P', 'rank':2});
		await sqlInsert('g_privilege', {'gameID':gameID, 'privilegeID':3, 'slot':opponentSlot, 'rank': 1});

		trace(`gameID#${gameID} initialized`, 1);
		return gameID;
		*/
	}
	
initGame(10,12);
