<?php

/**
 * Requires ABSPATH guards when generated PHP executes at file scope.
 *
 * @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\SafetyPhpHelper;
use LolaCore\Builder\Safety\SafetyRuleInterface;

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

/**
 * PCP-inspired direct file access check without an AST dependency.
 */
class DirectFileAccessRule implements SafetyRuleInterface {

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

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

		if (! $this->requiresDirectAccessGuard($php)) {
			return array();
		}

		if ($this->hasDirectAccessProtection($php)) {
			return array();
		}

		return array(
			array(
				'severity' => 'error',
				'code'     => $this->id(),
				'message'  => __('This PHP file runs code at load time but is missing a direct-access guard. Add: if ( ! defined( \'ABSPATH\' ) ) { exit; }', 'lolacore'),
				'line'     => 1,
			),
		);
	}

	private function requiresDirectAccessGuard( string $php ): bool {
		$clean = SafetyPhpHelper::stripComments($php);

		if (preg_match('/\b(add_action|add_filter|remove_action|remove_filter|register_activation_hook|register_deactivation_hook|register_uninstall_hook)\s*\(/i', $clean) === 1) {
			return true;
		}

		if (preg_match('/^\s*function\s+\w+\s*\(/im', $clean) === 1) {
			return true;
		}

		if (preg_match('/\bdefine\s*\(/i', $clean) === 1) {
			return true;
		}

		return false;
	}

	private function hasDirectAccessProtection( string $php ): bool {
		$lines       = explode("\n", $php);
		$first_lines = implode("\n", array_slice($lines, 0, 50));
		$beginning   = SafetyPhpHelper::stripComments($first_lines);
		$beginning   = preg_replace('/^\s*<\?php\s*/i', '', $beginning) ?? $beginning;
		$beginning   = trim($beginning);

		$patterns = array(
			"/defined\s*\(\s*(?:constant_name\s*:\s*)?['\"]ABSPATH['\"]\s*\)\s*(?:\|\||or)\s*(?:exit|die)\s*(?:\([^)]*\))?\s*;/i",
			"/defined\s*\(\s*(?:constant_name\s*:\s*)?['\"]WPINC['\"]\s*\)\s*(?:\|\||or)\s*(?:exit|die)\s*(?:\([^)]*\))?\s*;/i",
			"/if\s*\(\s*!\s*defined\s*\(\s*(?:constant_name\s*:\s*)?['\"]ABSPATH['\"]\s*\)\s*\)\s*(?:\{|exit|die)/i",
			"/if\s*\(\s*!\s*defined\s*\(\s*(?:constant_name\s*:\s*)?['\"]WPINC['\"]\s*\)\s*\)\s*(?:\{|exit|die)/i",
		);

		foreach ($patterns as $pattern) {
			if (preg_match($pattern, $beginning) === 1) {
				return true;
			}
		}

		return false;
	}
}
