<?php
/**
 * PHP/JS snippet runtime — ships with the Pro Code Snippet module only.
 *
 * Secure design (rafter-secure-design / auth):
 * - Identity: site admin (manage_options) authoring snippets.
 * - AuthZ: The whole Code Snippet module is Pro. Lite never ships this file.
 * - Untrusted input: user PHP/JS runs only after threat scanning in Module.
 *
 * @package CodeSnippet
 */

namespace CodeSnippet;

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

/**
 * Executes PHP/JS snippets for the Pro Code Snippet module.
 */
final class PremiumPhpJsRuntime {

	public static function isReady(): bool {
		return true;
	}

	/**
	 * Run raw PHP (no opening tag) in the global namespace.
	 */
	/**
	 * @param callable(string):void|null $before_include Receives the temp file path before include so callers can attribute later hook fatals.
	 */
	public static function run( string $code, ?callable $before_include = null ): void {
		if ( $code === '' ) {
			return;
		}

		if ( apply_filters( 'wpps_code_snippet_use_eval', false, $code ) ) {
			if ( function_exists( 'wp_powersuite_code_snippet_eval' ) ) {
				\wp_powersuite_code_snippet_eval( $code );
			}
			return;
		}

		$file = self::createTempPhpSnippetFile( $code );
		if ( $file !== '' ) {
			if ( $before_include !== null ) {
				$before_include( $file );
			}
			try {
				include $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.NotAbsolutePath -- Temp snippet file in get_temp_dir().
			} finally {
				wp_delete_file( $file );
			}
			return;
		}

		if ( function_exists( 'wp_powersuite_code_snippet_eval' ) ) {
			\wp_powersuite_code_snippet_eval( $code );
		}
	}

	/**
	 * Include a path already validated by Module::resolveAllowedPhpSnippetFile().
	 */
	public static function includeResolvedFile( string $resolved ): void {
		include $resolved; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.NotAbsolutePath
	}

	public static function wrapJs( string $code, string $handle = 'wpps-cs-js' ): string {
		$code = Module::stripJsTagsForStorage( $code );
		if ( $code === '' ) {
			return '';
		}

		\WP_PowerSuite\Core\InlineAssets::scriptNow( $handle, $code );
		return '';
	}

	public static function createTempPhpSnippetFile( string $code ): string {
		$dir = get_temp_dir();
		$dir = is_string( $dir ) ? trailingslashit( wp_normalize_path( $dir ) ) : '';
		if ( $dir === '' ) {
			return '';
		}

		$payload = '<' . '?php' . "\n" . $code . "\n";
		$tmp     = $dir . 'wpps_snip_' . bin2hex( random_bytes( 8 ) ) . '.php';
		if ( file_put_contents( $tmp, $payload ) !== false ) {
			return $tmp;
		}

		$probe = tempnam( $dir, 'wps' );
		if ( ! is_string( $probe ) || $probe === '' ) {
			return '';
		}
		$named = $dir . 'wpps_snip_' . bin2hex( random_bytes( 8 ) ) . '.php';
		if ( ! @rename( $probe, $named ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename -- tempnam() fallback to a wpps_snip_ name.
			wp_delete_file( $probe );
			return '';
		}
		if ( file_put_contents( $named, $payload ) === false ) {
			wp_delete_file( $named );
			return '';
		}

		return $named;
	}
}
