<?php

namespace Planaday\Html\Tags\Utility\ArrayDisplay;

use Planaday\Html\HtmlParser;
use Planaday\Html\Tags\Tag;
use Planaday\Utility\Debug\ToArray;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Traversable;

class ArrayDisplay extends Tag {
	const TAG = 'utility-array-display';
	const DEFAULT_TEMPLATE = 'arrayDisplay';
	const ARRAY_DISPLAY_CONTEXT = 'arrayDisplay';
	const INDEX_TO_DISPLAY_ATTRIBUTE = self::ATTRIBUTE_PREFIX . 'index-to-display';

	/**
	 * @param Container $registry
	 *
	 * @throws InjectionImpossibleException
	 */
	public function __construct(Container $registry) {
		parent::__construct(__DIR__, self::DEFAULT_TEMPLATE, $registry);
	}

	public function buildTag(): string {
		$displayArray = $this->context[self::ARRAY_DISPLAY_CONTEXT] ?? null;
		$index = $this->attributes[self::INDEX_TO_DISPLAY_ATTRIBUTE] ?? null;

		if ($displayArray instanceof ToArray){
			$displayArray = $displayArray->toArray();
		}

		if (!is_array($displayArray)){
			$this->logError(self::TAG . ' was called without array in ARRAY_DISPLAY context', $displayArray);
			return '';
		}

		if ($index !== null){
			$displayArray = $displayArray[$index] ?? null;
		}

		$parser = $this->getNewParser();

		switch ($this->attributes[self::TEMPLATE_ATTRIBUTE] ?? null){
			case 'tableDisplay':
				$this->setDataTable($displayArray, $parser);
				break;
			default:
				$parser->setUnsafeData('arrayDisplay', $this->buildDataArray($displayArray));
				break;
		}

		$parser->addStylesheet($this->getStylePath());
		return $parser->parse($this->getTemplate());
	}

	private function setDataTable(mixed $data, HtmlParser $parser): void {
		if (is_array($data) && count($data) == 0){
			$this->logWarning(self::TAG . ' was called with an empty array');
			$parser->setUnsafeData('headers', "<th> - </th>");
			$parser->setUnsafeData('rows', "<tr><td> <pad-translate>Niets te laten zien</pad-translate> </td></tr>");
			return;
		}

		if ($data instanceof Traversable) $data = iterator_to_array($data);

		if (!is_array($data) || !isset($data[0]) || !is_array($data[0])){
			$this->logError(self::TAG . ' was called without array in ARRAY_DISPLAY context');
			$parser->setUnsafeData('headers', "<th>Invalid Data</th>");
			$parser->setUnsafeData('rows', "<tr><td>Invalid Data for table: " . htmlspecialchars(print_r($data, true)) . "</td></tr>");
			return;
		}

		$headers = '';
		foreach ($data[0] as $key => $value){
			$headers .= '<th>' . htmlspecialchars($key) . '</th>';
		}
		$parser->setUnsafeData('headers', $headers);

		$rows = '';
		foreach ($data as $row) {
			$rows .= '<tr>';
			foreach ( $row as $value ) {
				$rows .= '<td>' . $this->getValueDataCell($value, false) . '</td>';
			}
			$rows .= '</tr>';
		}
		$parser->setUnsafeData('rows', $rows);
	}

	private function buildDataArray(mixed $data): string{
		$output = '';

		if ( $data instanceof ToArray){
			$data = $data->toArray();
		}

		if (!is_array($data)) return '<div class="pad-keyItem"> returned value </div>' . $this->getValueDataCell($data);

		foreach ($data as $key => $value){
			$output .= '<div class="pad-keyItem">' . htmlspecialchars($key) . htmlspecialchars(is_object($value)?'(' . str_replace('\\', "\\ ",get_class($value)) . ')':'') . '</div>';
			$output .= $this->getValueDataCell($data);
		}

		return $output;
	}

	private function getValueDataCell(mixed $data, bool $allowRecursive = true):string {
		if ($data instanceof ToArray){
			$data = $data->toArray();
		}

		if (is_object($data)){
			return '<div class="pad-dataItem"> (' . htmlspecialchars(get_class($data)) . ') ' . htmlspecialchars(print_r($data, true)) . '</div>';
		}

		if (is_string($data)) return '<div class="pad-dataItem"> "' . htmlspecialchars($data) . '" </div>';
		if (is_numeric($data)) return '<div class="pad-dataItem"> ' . $data . ' </div>';
		if (is_bool($data)) return '<div class="pad-dataItem"> ' . ($data ? "TRUE" : "FALSE") . ' </div>';
		if ($data === null) return '<div class="pad-dataItem"> ' . "NULL" . ' </div>';

		if (is_array($data) && $allowRecursive) return '<div class="pad-dataItem pad-array"> ' . $this->buildDataArray($data) . ' </div>';

		return '<div class="pad-dataItem"> ' . htmlspecialchars(print_r($data, true)) . ' </div>';
	}
}