const HEIGHT = 300;
const WIDTH = 250;
const SIDE = 50;
const MARGIN_TOP = 50;
const MARGIN_BOTTOM = 25;

let myScore = 0;
let myGuess = null;
let myGuesses = null;
let myProgress = null;
let myResults = null;
let lastWord = null;

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

let client = null;

function main() {
	start();
}

function start() {
	ctx.font = '25px Monospace';
	ctx.textBaseline = 'middle';
	ctx.textAlign = 'center';

	addKeydownListener();
	addKeypressListener();
	addSkipButtonListener();

	reset();
	repaint();

	let webSocketProtocol = 'ws';
	if (location.protocol.startsWith('https')) {
		webSocketProtocol = 'wss';
	}

	client = new StompJs.Client({
		brokerURL: `${webSocketProtocol}://${location.host}/stomp`,
		connectHeaders: {},
		//reconnectDelay: 5000, // TODO: implement reconnect functionality
		reconnectDelay: 0, // Disable automatic reconnects
		heartbeatIncoming: 25000, // send PING every 25 seconds
		heartbeatOutgoing: 25000, // receive PONG every 25 seconds
		//debug: function (str) { console.log(str); } // Print debug logs
	});

	client.onConnect = function(frame) {
		subscribeToPracticeGame();
		subscribeToPracticeReports();
		subscribeToPracticeWordSkipped();
		client.publish({destination: '/app/practiceGame'});
	}

	client.activate();
}

// special keys
function addKeydownListener() {
	document.addEventListener('keydown', function(e) {
		if (e.key === 'Backspace') {
			e.preventDefault();
			myGuess = myGuess.substr(0, myGuess.length - 1);
			repaint();
		}
		else if (e.key === 'Enter') {
			e.preventDefault();
			if (myGuess.length === 5) {
				client.publish({destination: '/app/practiceGuess', body: myGuess});
				myGuess = '';
				repaint();
			}
		}
	});
}

// characters
function addKeypressListener() {
	document.addEventListener('keypress', function(e) {
		const key = e.key.toUpperCase();
		if (myGuess.length < 5 && isCharacter(key)) {
			myGuess += key;
			repaint();
		}
	});
}

// skip button
function addSkipButtonListener() {
	document.getElementById('skipButton').addEventListener('click', function(e) {
		client.publish({destination: '/app/practiceSkip'});
	});
}

function drawMyBoard() {
	const x = 25;
	const y = MARGIN_TOP;
	drawScore(x, y, myScore);
	drawInput(x, y, myGuess);
	const yStart = drawGuesses(x, y, myGuesses, myResults);
	drawHint(x, yStart, myProgress);
	drawGrid(x, y);
}

function drawLastWord() {
	if (lastWord) {
		const x = canvas.width / 2;
		const y = canvas.height - MARGIN_BOTTOM / 2;
		ctx.fillStyle = 'black';
		ctx.fillText(lastWord.toUpperCase(), x, y);
	}
}

function drawScore(x, y, score) {
	const scoreX = x + WIDTH / 2;
	const scoreY = y - 25;
	ctx.fillStyle = 'black';
	ctx.fillText(score, scoreX, scoreY);
}

function drawGrid(xOrigin, yOrigin) {
	ctx.beginPath();
	for (let x = 0; x <= WIDTH; x += SIDE) {
		ctx.moveTo(xOrigin + x, yOrigin);
		ctx.lineTo(xOrigin + x, yOrigin + HEIGHT);
	}
	for (let y = 0; y <= HEIGHT; y += SIDE) {
		ctx.moveTo(xOrigin, yOrigin + y);
		ctx.lineTo(xOrigin + WIDTH, yOrigin +  y);
	}
	ctx.strokeStyle = 'black';
	ctx.stroke();
}

function drawInput(xOrigin, yOrigin, input) {
	ctx.fillStyle = 'green';
	let x = xOrigin + SIDE * 0.5;
	const y = yOrigin + SIDE * 0.5;
	for (let i = 0; i < myGuess.length; i++) {
		ctx.fillText(myGuess[i], x, y);
		x += SIDE;
	}
}

function drawGuesses(xOrigin, yOrigin, guesses, results) {
	let y = yOrigin + SIDE * 1.5;
	const numGuesses = Math.min(4, guesses.length);
	for (let i = 0; i < numGuesses; i++) {
		let x = xOrigin + SIDE * 0.5;
		const guess = guesses[guesses.length - numGuesses + i];
		const result = results[results.length - numGuesses + i];
		for (let j = 0; j < 5; j++) {
			if (result[j] === 1) {
				ctx.fillStyle = 'yellow';
				ctx.fillRect(x - SIDE * 0.5, y - SIDE * 0.5, SIDE, SIDE);
			} else if (result[j] === 2) {
				ctx.fillStyle = 'orange';
				ctx.fillRect(x - SIDE * 0.5, y - SIDE * 0.5, SIDE, SIDE);
			}
			ctx.fillStyle = 'green';
			ctx.fillText(guess[j], x, y);
			x += SIDE;
		}
		y += SIDE;
	}
	return y;
}

function drawHint(xOrigin, yOrigin, progress) {
	let x = xOrigin + SIDE * 0.5;
	for (let i = 0; i < 5; i++) {
		ctx.fillText(progress[i], x, yOrigin);
		x += SIDE;
	}
}

function isCharacter(key) {
	return key >= "A" && key <= "Z";
}

function repaint() {
	// clear the canvas
	ctx.clearRect(0, 0, canvas.width, canvas.height);

	// draw the components
	drawMyBoard();
	drawLastWord();
}

function reset(firstLetter, clearScore) {
	if (!firstLetter) {
		firstLetter = '';
	}
	myGuess = '';
	myGuesses = [];
	myProgress = [firstLetter, '', '', '', ''];
	myResults = [];
	if (clearScore) {
		myScore = 0;
	}
}

function subscribeToPracticeGame() {
	client.subscribe('/user/topic/practiceGame', function(message) {
		const firstLetter = message.body;
		reset(firstLetter, true);
		repaint();
		document.getElementById('skipDiv').classList.remove('hidden');
	});
}

function subscribeToPracticeReports() {
	client.subscribe('/user/topic/practiceReports', function(message) {
		console.log('My report: ' + message.body);
		const report = JSON.parse(message.body);
		if (report.correct === true) {
			const guess = report.guess;
			const firstLetter = report.firstLetter;
			myScore = myScore + 100;
			lastWord = guess;
			reset(firstLetter, false);
			repaint();
		} else {
			const guess = report.guess;
			const result = report.result;
			if (result[0] === 9) {
				myGuesses.push('-----');
			} else {
				for (let i = 0; i < 5; i++) {
					if (result[i] === 2) {
						myProgress[i] = guess[i];
					}
				}
				myGuesses.push(guess);
			}
			myResults.push(result);
			repaint();
		}
	});
}

function subscribeToPracticeWordSkipped() {
	client.subscribe('/user/topic/practiceWordSkipped', function(message) {
		const firstLetter = message.body;
		lastWord = null;
		reset(firstLetter, false);
		repaint();
	});
}

main();
