<?php

namespace Planaday\Html\Parsers\TagNameParsers;

use Planaday\Html\NodeTags\Tag;
use Planaday\Utility\Debug\Log\Logging;
use Planaday\Utility\DependencyInjection\Attributes\Scoped;

#[Scoped]
class PadTagNameParser implements TagNameParser {
	use Logging;

	/** @var array<string, class-string<Tag>> */
	protected array $baseRegistry = [];
	const TAG_CLASS_NAMESPACE = 'Planaday\Html\NodeTags';

	/** @var array<string, class-string<Tag>> */
	protected array $tagCache = [];

	/**
	 * @inheritDoc
	 */
	public function parseTagName( string $tagName, array $tagRegistry ): string|null {
		if ( ! str_starts_with( $tagName, "pad-" ) ){
			return null;
		}

		$tagName = substr($tagName, 4);

		$this->logDebug( "parsing tag name: " . $tagName );

		if (isset($this->tagCache[$tagName])){
			$this->logDebug( "tag name was found in cache: " . $this->tagCache[$tagName] );
			return $this->tagCache[$tagName];
		}

		$tagNameParts = explode('-', $tagName);

		if (count($tagNameParts) == 1 && (isset($tagRegistry[$tagNameParts[0]]) || isset($this->baseRegistry[$tagNameParts[0]]))){
			$class = $tagRegistry[$tagNameParts[0]] ?? $this->baseRegistry[$tagNameParts[0]];
			$this->logDebug( "tag name is a registered tag: $class" );
			return $class;
		}

		$className = self::TAG_CLASS_NAMESPACE;
		$lastTagNamePart = '';

		foreach ($tagNameParts as $tagNamePart){
			$camelCaseTagNamePart = ucfirst($tagNamePart);
			$camelCaseTagNamePart = preg_replace_callback('/_([a-z])/', function($matches){ return strtoupper($matches[1]); }, $camelCaseTagNamePart);

			$this->logDebug( "current class name: $className" );
			$this->logDebug( "next tag name part: $camelCaseTagNamePart" );

			if (class_exists($className) && is_a($className, TagNameRegister::class, true)){
				$className = $className::getClass( $camelCaseTagNamePart );
				$this->logDebug( "tag name is registered: $className" );
				continue;
			}

			$className .= '\\' . $camelCaseTagNamePart;
			$lastTagNamePart = $camelCaseTagNamePart;
		}

		if (class_exists($className) && is_a($className, Tag::class, true)){
			$this->logDebug( "tag name was found: $className, adding to cache" );
			$this->tagCache[$tagName] = $className;
			return $className;
		}

		$className .= '\\' . $lastTagNamePart;

		if (class_exists($className) && is_a($className, Tag::class, true)){
			$this->logDebug( "tag name was found deeper: $className, adding to cache" );
			$this->tagCache[$tagName] = $className;
			return $className;
		}

		if (count($tagNameParts) > 1){
			$this->logDebug( "tag name does not exist, caching null" );
			$this->tagCache[$tagName] = null;
		}

		return null;
	}

	/**
	 * @param array<string, class-string<Tag>> $tagRegistry
	 *
	 * @return void
	 */
	public function setBaseRegistry( array $tagRegistry ): void {
		$this->baseRegistry = $tagRegistry;
	}
}