<?php
namespace Modules\Admin\Server\Logs;

class ModelGenerateReportCoreAppError
{
	public function generate($outputFile, $listingParams)
	{
		$model = new Model();
		$listingParams->setCurrentPage(0);
		$listingParams->setResultsPerPage(PHP_INT_MAX);

		$model->list_execute($listingParams);
		$listRows = $model->list_getRecordsList();

		$fileHandle = fopen($outputFile, 'w');

		fwrite($fileHandle, <<<'HTML'
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>TINA core error logs</title>

	<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>

	<style>
		pre.output {
			margin-top: 2em;
		}
		span.id {
			float: right;
			color: #88f;
			padding: 0 0.5em;
		}
		span.addTime {
			float: right;
			color: #888;
			padding: 0 0.5em;
		}
		div.line {
			line-height: 1;
			border-bottom: 1px solid #444;
			padding-bottom: 0.5em;
		}
		div.line.E_NOTICE >div.message >span.type {
			background-color: hsl(90, 75%, 70%);
		}
		div.line.E_WARNING >div.message >span.type {
			background-color: hsl(30, 75%, 80%);
		}
		div.line.E_ERROR >div.message >span.type {
			background-color: hsl(5, 75%, 80%);
		}

		div.line div.file {
			margin-left: 2em;
			margin-top: 1em;
			color: hsl(120, 50%, 25%);
		}
		div.line div.stacktrace {
			margin-left: 2em;
			margin-top: 1em;
			color: hsl(180, 50%, 25%);
		}

		section.log-header {
			position: fixed;
			width: 100%;
			top: 0;
			left: 0;
			background-color: hsl(180,  25%, 95%);
			border-bottom: 2px solid hsl(180,  25%, 90%);
			z-index: 1;
		}

		.log-header >#stats {
			float: right;
			margin-left: 0.5em;
			padding-left: 0.5em;
			border-left: 1px solid #ccc;

			font-size: 0.75em;
			color: hsl(180,  25%, 33%);
		}
	</style>
</head>
<body>

<section class="log-header">
	<span 	id="stats">loading ...</span>
	<button onClick="deleteDuplicates()">delete duplicates</button>
	<button onClick="sortByDate()">sort everything by date</button>
	<button onClick="sortByMessage()">sort everything by message</button>
	<button onClick="sortByFile()">sort everything by file</button>
	<button onClick="sortByStacktrace()">sort everything by stacktrace</button>

	<script>
		function deleteDuplicates() {
			let uniqueHashes = [...new Set($('pre.output >div.line').map((i, a) => {
				return $(a).attr('data-hash');
			}))];

			let newOutput = '';
			uniqueHashes.forEach((h) => {
				newOutput+= $(`pre.output >div.line[data-hash=${h}]`)[0].outerHTML;
			});
			// seems it's faster to remove the whole element and add it back
			$(`pre.output`).remove();
			$('.log-header').after(`<pre class="output">${newOutput}</pre>`);

			generateStats();
		}

		function sortByDate() {
			let rows = $('pre.output >div.line')
				.sort( (a, b) => {
					let a1 = $(a).find('span.addTime').html();
					let b1 = $(b).find('span.addTime').html();

					if (a1==null) {
						a1 = '';
					}

					if (b1==null) {
						b1 = '';
					}

					return a1.localeCompare(b1);
				}
			);

			$('pre.output').append(rows);
		}

		function sortByMessage() {
			let rows = $('pre.output >div.line')
				.sort( (a, b) => {
					let a1 = $(a).find('div.message').html();
					let b1 = $(b).find('div.message').html();

					if (a1==null) {
						a1 = '';
					}

					if (b1==null) {
						b1 = '';
					}

					return a1.localeCompare(b1);
				}
			);

			$('pre.output').append(rows);
		}

		function sortByFile() {
			let rows = $('pre.output >div.line')
				.sort( (a, b) => {
					let a1 = $(a).find('div.file').html();
					let b1 = $(b).find('div.file').html();

					if (a1==null) {
						a1 = '';
					}

					if (b1==null) {
						b1 = '';
					}

					return a1.localeCompare(b1);
				}
			);

			$('pre.output').append(rows);
		}

		function sortByStacktrace() {
			let rows = $('pre.output >div.line')
				.sort( (a, b) => {
					let a1 = $(a).find('div.stacktrace').html();
					let b1 = $(b).find('div.stacktrace').html();

					if (a1==null) {
						a1 = '';
					}

					if (b1==null) {
						b1 = '';
					}

					return a1.localeCompare(b1);
				}
			);

			$('pre.output').append(rows);
		}

		function generateStats() {
			let totalRows = new Intl.NumberFormat().format($('pre.output >div.line').length);
			$('#stats').html(`got ${totalRows} rows`);
		}

		$(window).on( "load", function() {
			generateStats();
		});
	</script>
</section>

<pre class="output">
HTML
);


		$rowIndex = 0;
		$reportedMessages = [];

		foreach ($listRows as $listRow) {
			if (!preg_match("/^\[MAIN::__logCoreAppError\].+/", $listRow['message'])) {
				continue;
			}

			$logRow = $model->getFullLogDetails($listRow['id']);
			if (!$logRow) {
				continue;
			}
			if (!$logRow['context']) {
				continue;
			}

			$messageHash = md5($listRow['message'] . $logRow['context']['$errfile'] . $logRow['context']['$stacktrace']);
			if (!$this->shouldReportRow($messageHash)) {
				continue;
			}

			$reportedMessages[$messageHash] = true;

			$colorIndex = strlen($listRow['message']??'') + strlen($logRow['context']['$errfile']??'') + strlen($logRow['context']['$stacktrace']??'');
			$colorIndex = (round($colorIndex/10) * 10) % 360;

			$fileContent = sprintf("<div style='background-color: hsl(%d, %d%%, %d%%);' class='line %s' data-hash='%s' ><span class='addTime'>%s</span><span class='id'>%s</span><div class='message'>%s</div><div class='file'>%s</div><div class='stacktrace'>%s</div></div>",
				$colorIndex, 66, 92,
				$logRow['context']['$errorLevel'],
				$messageHash,
				$listRow['addTime'],
				$listRow['id'],
				$this->cleanupMessage($listRow['message']),
				$logRow['context']['$errfile'],
				implode("\n", $logRow['stacktrace']),
			);

			fwrite($fileHandle, $fileContent);
			$rowIndex++;
		}

		fwrite($fileHandle, <<<HTML
</pre>
</body>
</html>
HTML
	);

		fclose($fileHandle);

		return $this;
	}

	/**
	 * Filter the log text
	 * @param $logStr
	 * @return string
	 */
	protected function cleanupMessage($message)
	{
		$message = preg_replace("/^\[MAIN::__logCoreAppError\][\s]*(PHP message:[\s]*)?/", "", $message);
		$message = preg_replace("/^(E_[A-Z]+)/", "<span class='type'>$1</span>", $message);
		return $message;
	}

	protected function shouldReportRow(string $messageHash)
	{
		return true;
	}

}
