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

class ModelGenerateReportFluXLogsRaw
{
	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>FluX 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;
		}
		span.addTime {
			float: left;
			color: #888;
		}
		h2 {
			margin-top: 0;
			white-space: normal;
		}

		div.header {
			font-family: serif;
			position: sticky;
			top: 25px;
		}
		div.header.row-0 { background-color: hsl(50,  100%, 90%); border: 2px solid hsl(50,  100%, 70%); }
		div.header.row-1 { background-color: hsl(0,   100%, 90%); border: 2px solid hsl(0,   100%, 70%); }
		div.header.row-2 { background-color: hsl(134, 100%, 90%); border: 2px solid hsl(134, 100%, 70%); }
		div.header.row-3 { background-color: hsl(253, 100%, 90%); border: 2px solid hsl(253, 100%, 70%); }


		div.data {
			font-family: monospace;
		}
		div.data >div.row {
			transition: opacity 1.5s;
		}
		div.data >div.row.faded {
			opacity:   0.33;
			font-size: 0.01em;
			line-height: 2px;
		}
		div.data >div.row.faded:hover {
			opacity:   0.66;
			font-size: 1em;
			line-height: initial;
		}

		div.data.row-0 { background-color: hsl(50,  100%, 97%); border: 2px solid hsl(50,  100%, 70%); }
		div.data.row-1 { background-color: hsl(0,   100%, 97%); border: 2px solid hsl(0,   100%, 70%); }
		div.data.row-2 { background-color: hsl(134, 100%, 97%); border: 2px solid hsl(134, 100%, 70%); }
		div.data.row-3 { background-color: hsl(253, 100%, 97%); border: 2px solid hsl(253, 100%, 70%); }

		/** https://paletton.com/#uid=3001g0kJS6KvW5fuP8MNdeqCnl7 */
		div.data >div.row.level-0 { color: hsl(0,  10%, 75%); }
		div.data >div.row.level-1 { color: hsl(0,  50%, 45%); }
		div.data >div.row.level-2 { color: hsl(0,  70%, 33%); }
		div.data >div.row.level-3 { color: hsl(0,  80%, 25%); }
		div.data >div.row.level-4 { color: hsl(0,  95%, 17%); }
		div.data >div.row.level-5 { color: hsl(0, 100%, 7%); }

		/** https://paletton.com/#uid=3001g0k3V4WaYgf7Lb1ac80gJaQ */
		div.data >div.row >span.date { color: #817C55; font-size: 0.8em;}


		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;
		}
	</style>
</head>
<body>

<section class="log-header">
	<button onClick="sortByDate()">sort everything by date</button>
	<button onClick="hideLevel0()">hide level 0</button>
	<input type="text" placeholder="filter" onChange="filterText($(this).val())" />

	<script>
		function sortByDate() {
			let rows = $('div.data >div.row')
				.sort( (a, b) => {
					let a1 = $(a).find('span.date').html();
					let b1 = $(b).find('span.date').html();

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

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

					return a1.localeCompare(b1);
				}
			);

			$('pre.output >div.header').remove();
			$('pre.output >div.data').remove();

			$('pre.output').append($('<div class="data">').append(rows));
		}

		filterTextDelayed_timer = null;
		function filterTextDelayed(searchText) {
			if (filterTextDelayed_timer) {
				clearTimeout(filterTextDelayed_timer);
				filterTextDelayed_timer = null;
			}

			filterTextDelayed_timer = setTimeout(() => {
				filterText(searchText);
			}, 1.5 * 1000);
		}

		function filterText(searchText) {
			if (filterTextDelayed_timer) {
				clearTimeout(filterTextDelayed_timer);
				filterTextDelayed_timer = null;
			}

			let rx = new RegExp(searchText, "gi");
			$('div.data >div.row.faded').removeClass('faded');
			$('div.data >div.row').map( (i, r) => {
				let row = $(r);
				if (!row.text().match(rx)) {
					row.addClass('faded');
				}
			});
		}

		function hideLevel0() {
			$('div.data >div.row.level-0').remove();
		}
	</script>
</section>

<pre class="output">
HTML
);


		$rowIndex = 0;
		foreach ($listRows as $listRow) {
			$logRow = $model->getLogDetails($listRow['id']);
			if (!$logRow) {
				continue;
			}
			if (!$logRow['context']) {
				continue;
			}
			$loggerElement = $logRow['context']['log'];
			if (!($loggerElement instanceof \Engine\Logger\Context\HtmlFluXLogs)) {
				continue;
			}

			$fileContent = sprintf("<div class='header row-%d'><span class='addTime'>%s</span><span class='id'>%s</span>&nbsp<h2>%s</h2></div><div class='data row-%d'>%s</div>\n",
				$rowIndex%4,
				$listRow['addTime'],
				$listRow['id'],
				$listRow['message'],

				$rowIndex%4,
				$this->highlightLogs($this->filterLog($loggerElement->getRawValue()))
			);

			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 filterLog($logStr)
	{
		return $logStr;
	}

	/**
	 * Highlight the log text
	 * @param string $logStr The log text
	 * @return string
	 */
	protected function highlightLogs($logStr)
	{
		$logStrArr = explode("\n", $logStr);
		$currentLogLevel = null;
		$prevLogLevel = null;
		$logStrArrRewritten = [];
		$logStrTempStack = [];
		$prevLineHineHasLevel = false;
		foreach ($logStrArr as $lineStr) {
			$lineHasLevel = false;
			$matches = [];
			if (preg_match("/^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+, (?P<logLevel>[0-9])\]/", $lineStr, $matches)) {
				$currentLogLevel = $matches['logLevel'];
				$lineHasLevel = true;
			}
			if ((!$prevLineHineHasLevel && $lineHasLevel) || ($prevLineHineHasLevel && $lineHasLevel)) {
				$logStrArrRewritten[]= sprintf("<div class='row level-%d'>%s</div>", $prevLogLevel, $this->highlightLogLine(implode("\n", $logStrTempStack)));
				$logStrTempStack = [];
			}

			$logStrTempStack[]= $lineStr;
			$prevLogLevel = $currentLogLevel;
			$prevLineHineHasLevel = $lineHasLevel;
		}

		if ($logStrTempStack) {
			$logStrArrRewritten[]= sprintf("<div class='row level-%d'>%s</div>", $currentLogLevel, $this->highlightLogLine(implode("\n", $logStrTempStack)));
		}

		return implode("", $logStrArrRewritten);
	}

	/**
	 * Highlight the log text line
	 * @param $logStr
	 * @return string
	 */
	protected function highlightLogLine($logStr)
	{
		return preg_replace_callback("/^(?P<date>\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+, (?P<logLevel>[0-9])\])(?P<rest>.*)/", function($matches) {
			return sprintf("<span class='date'>%s</span>%s", $matches['date'], $matches['rest']);
		}, $logStr);
	}

}
