<?php

/**
 * Detects vendor FQCN references missing namespace backslashes.
 *
 * @package LolaCore\Builder\Safety\Rules
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Builder\Safety\Rules;

use LolaCore\Builder\Safety\SafetyContext;
use LolaCore\Builder\Safety\SafetyRuleInterface;

if (! defined('ABSPATH')) {
	exit;
}

/**
 * Flags glued vendor class names that parse as valid PHP but fatals at runtime.
 */
class StrippedVendorNamespaceRule implements SafetyRuleInterface {

	public function id(): string {
		return 'stripped_vendor_namespace';
	}

	/**
	 * @inheritDoc
	 */
	public function analyze( string $php, SafetyContext $context ): array {
		unset($context);

		$roots = 'Automattic|Symfony|Psr|Monolog|Composer|GuzzleHttp|WpOrg';

		$patterns = array(
			'/\b(?:' . $roots . ')[A-Z]\w*(?=\s*::)/',
			'/\bnew\s+((?:' . $roots . ')[A-Z]\w*)/',
		);

		foreach ($patterns as $pattern) {
			if (preg_match($pattern, $php, $matches) === 1) {
				$name = isset($matches[1]) ? $matches[1] : $matches[0];
				$line = $this->lineNumberForMatch($php, (string) $name);

				return array(
					array(
						'severity' => 'fatal',
						'code'     => $this->id(),
						'message'  => sprintf(
							/* translators: %s: malformed class reference missing namespace separators */
							__('The class reference "%s" is missing its namespace backslashes, so it points to a class that does not exist. Use the fully-qualified name with a leading and separating backslash, e.g. \\Automattic\\WooCommerce\\Utilities\\FeaturesUtil::declare_compatibility(...).', 'lolacore'),
							trim($name)
						),
						'line'     => $line,
					),
				);
			}
		}

		return array();
	}

	private function lineNumberForMatch( string $php, string $needle ): int {
		$position = strpos($php, $needle);
		if ($position === false) {
			return 0;
		}

		return substr_count(substr($php, 0, $position), "\n") + 1;
	}
}
