<?php

namespace Planaday\Html\Parsers\NodeParsers;

use DOMCdataSection;
use DOMElement;
use DOMNode;
use Planaday\Html\Nodes\NodeData;
use Planaday\Html\Nodes\ParserNode;
use Planaday\Platform\PlatformAbstraction\UrlHandler;
use Planaday\Utility\Debug\Log\Logging;
use Planaday\Utility\DependencyInjection\Attributes\Scoped;

#[Scoped]
class RelativeSrcFixer implements NodeParser {
	use Logging;
	protected NodeData $nodeData;
	protected string $currentDir;

	public function __construct(protected UrlHandler $urlHandler) {}

	public function setNodeData( NodeData $nodeData ): void {
		$this->nodeData = $nodeData;
	}

	public function modifyNode( DOMNode&ParserNode $node ): void {
		if ( ! isset( $this->nodeData )  ) {
			return;
		}

		$this->nodeData->data['autoGenerated'] ??= [];
		$this->currentDir = $this->nodeData->data['autoGenerated']['lastValidDir'] ?? '';
		if ( $node instanceof DOMElement){
			/** @var DOMElement&ParserNode $node */
			$this->sanitizeAttribute( $node, 'src' );
			$this->sanitizeAttribute( $node, 'href' );

			$tag = $node->getAssociatedTag();
			if ( $tag !== null ) {
				$newDir = $tag->getTagDir();
				if (!empty($newDir)) {
					$this->nodeData->data['autoGenerated']['lastValidDir'] = $newDir;
				}
			}
		}

		if ( $node instanceof DOMCdataSection ){
			/** @var DOMCdataSection&ParserNode $node */
			$this->modifyCdata($node);
		}
	}

	protected function sanitizeAttribute(DOMElement&ParserNode $element, string $attribute): void {
		if ( $element->hasAttribute($attribute) ) {
			$element->setAttribute(
				$attribute,
				$this->sanitizeUrl(
					$element->getAttribute($attribute)
				)
			);

			$element->getAssociatedTag()?->setAttribute(
				$attribute,
				$element->getAttribute($attribute)
			);
		}
	}

	protected function modifyCdata(DOMCdataSection $node): void {
		$replaceCallback = function($match) {
			return str_replace($match[1], $this->sanitizeUrl( $match[1] ), $match[0]);
		};

		$html = $node->data;

		$html = preg_replace_callback( "#@import\s+(?:url\()?\s*['\"]([^'\"]+)['\"]\s*\)?#", $replaceCallback, $html);
		$html = preg_replace_callback( "#^\s*import\s+['\"]([^'\"]+)['\"]\s*;\s*$#m", $replaceCallback, $html);
		$html = preg_replace_callback( "#^\s*import\s.*?\sfrom\s+['\"]([^'\"]+)['\"]\s*;\s*$#m", $replaceCallback, $html);
		$html = preg_replace_callback( "#\simport\s*\(\s*['\"]([^'\"]+)['\"]\s*#", $replaceCallback, $html);

		$node->data = $html;
	}

	protected function sanitizeUrl(string $url): string {
		$url = trim($url);

		if ( !str_starts_with($url, '../') ) return $url;

		$dir = $this->currentDir;
		$url = substr($url, 3);
		if (empty($dir)) return "/$url";

		while (str_starts_with($url, '../')){
			$url = substr($url, 3);
			$dir = dirname($dir);
		}

		return $this->urlHandler->getFileUrl($dir) . "/$url";
	}
}