<?php
/**
 * WeCodeArt Framework.
 *
 * WARNING: This file is part of the core WeCodeArt Framework. DO NOT edit this file under any circumstances.
 * Please do all modifications in the form of a child theme.
 *
 * @package 	WeCodeArt Framework
 * @subpackage 	Support\Modules\Security
 * @copyright   Copyright (c) 2025, WeCodeArt Framework
 * @since 		6.7.0
 * @version		6.7.0
 */

namespace WeCodeArt\Support\Modules;

defined( 'ABSPATH' ) || exit;

use WeCodeArt\Config\Traits\Singleton;

/**
 * Module Security Validation
 */
final class Security {

	use Singleton;

	/**
	 * Security validation results
	 *
	 * @var array
	 */
	private $validation_results = [];

	/**
	 * Security issues found
	 *
	 * @var array
	 */
	private $security_issues = [];

	/**
	 * Validate module security
	 *
	 * @param  string $module_path Module directory path
	 * @return bool
	 */
	public function validate_module( string $module_path ): bool {
		$this->validation_results = [];
		$this->security_issues = [];

		// Basic checks
		$this->check_required_files( $module_path );
		$this->check_php_syntax( $module_path );
		$this->check_suspicious_files( $module_path );

		// Log security issues
		if ( ! empty( $this->security_issues ) ) {
			$this->log_security_issues( $module_path );
		}

		return empty( $this->security_issues );
	}

	/**
	 * Check for suspicious files
	 *
	 * @param  string $module_path
	 * @return void
	 */
	private function check_suspicious_files( string $module_path ): void {
		$suspicious_patterns = [
			'\.(exe|bat|cmd|com|pif|scr|vbs)$',
			'\.(bak|backup|old|tmp)$',
			'(wp-config|\.env|\.htaccess)',
			'(eval|exec|system|shell_exec|passthru)',
			'(base64' . '_decode|gzinflate|gzuncompress)',
		];

		$files = new \RecursiveIteratorIterator(
			new \RecursiveDirectoryIterator( $module_path, \RecursiveDirectoryIterator::SKIP_DOTS )
		);

		foreach ( $files as $file ) {
			if ( $file->isFile() ) {
				$filename = $file->getFilename();
				$filepath = $file->getPathname();

				// Check filename patterns
				foreach ( $suspicious_patterns as $pattern ) {
					if ( preg_match( '/' . $pattern . '/i', $filename ) ) {
						$this->add_security_issue( 'suspicious_file', sprintf( 
							'Suspicious file found: %s', 
							str_replace( $module_path, '', $filepath )
						) );
					}
				}

				// Check file content for suspicious code
				$extension = pathinfo( $filename, PATHINFO_EXTENSION );
				if ( $extension === 'php' ) {
					$this->check_php_content( $filepath );
				} elseif ( $extension === 'js' ) {
					$this->check_js_content( $filepath );
				}
			}
		}
	}

	/**
	 * Check PHP file content for suspicious code
	 *
	 * @param  string $file_path
	 * @return void
	 */
	private function check_php_content( string $file_path ): void {
		$content = file_get_contents( $file_path );
		
		if ( ! $content ) {
			return;
		}

		$suspicious_functions = [
			'eval\s*\(',
			'exec\s*\(',
			'system\s*\(',
			'shell_exec\s*\(',
			'passthru\s*\(',
			'base64' . '_decode\s*\(',
			'gzinflate\s*\(',
			'gzuncompress\s*\(',
			'file_get_contents\s*\(\s*[\'"]\$_',
			'include\s*\(\s*[\'"]\$_',
			'require\s*\(\s*[\'"]\$_',
		];

		foreach ( $suspicious_functions as $pattern ) {
			if ( preg_match( '/' . $pattern . '/i', $content ) ) {
				$this->add_security_issue( 'suspicious_code', sprintf( 
					'Suspicious PHP code found in %s', 
					basename( $file_path )
				) );
			}
		}
	}

	/**
	 * Check JavaScript file content for suspicious code
	 *
	 * @param  string $file_path
	 * @return void
	 */
	private function check_js_content( string $file_path ): void {
		$content = file_get_contents( $file_path );
		
		if ( ! $content ) {
			return;
		}

		$suspicious_patterns = [
			'eval\s*\(',
			'Function\s*\(\s*[\'"]',
			'setTimeout\s*\(\s*[\'"]\s*[^)]*eval',
			'setInterval\s*\(\s*[\'"]\s*[^)]*eval',
			'document\.write\s*\(\s*[\'"]\s*<script',
			'innerHTML\s*=\s*[\'"]\s*<script',
			'outerHTML\s*=\s*[\'"]\s*<script',
			'location\s*=\s*[\'"]\s*javascript:',
			'window\.location\s*=\s*[\'"]\s*javascript:',
		];

		foreach ( $suspicious_patterns as $pattern ) {
			if ( preg_match( '/' . $pattern . '/i', $content ) ) {
				$this->add_security_issue( 'suspicious_code', sprintf( 
					'Suspicious JavaScript code found in %s', 
					basename( $file_path )
				) );
			}
		}
	}

	/**
	 * Check PHP syntax
	 *
	 * @param  string $module_path
	 * @return void
	 */
	private function check_php_syntax( string $module_path ): void {
		$files = new \RecursiveIteratorIterator(
			new \RecursiveDirectoryIterator( $module_path, \RecursiveDirectoryIterator::SKIP_DOTS )
		);

		foreach ( $files as $file ) {
			if ( $file->isFile() && pathinfo( $file->getFilename(), PATHINFO_EXTENSION ) === 'php' ) {
				$content = file_get_contents( $file->getPathname() );
				
				// Basic syntax check
				if ( $content && ! $this->is_valid_php_syntax( $content ) ) {
					$this->add_security_issue( 'syntax_error', sprintf( 
						'PHP syntax error in %s', 
						basename( $file->getPathname() )
					) );
				}
			}
		}
	}

	/**
	 * Check if PHP syntax is valid
	 *
	 * @param  string $code
	 * @return bool
	 */
	private function is_valid_php_syntax( string $code ): bool {
		// Remove comments and whitespace for basic check
		$code = preg_replace( '/\/\*.*?\*\//s', '', $code );
		$code = preg_replace( '/\/\/.*$/m', '', $code );
		
		// Check for basic PHP structure
		return strpos( $code, '<?php' ) !== false || strpos( $code, '<?=' ) !== false;
	}

	/**
	 * Check required files exist
	 *
	 * @param  string $module_path
	 * @return void
	 */
	private function check_required_files( string $module_path ): void {
		$required_files = [
			'index.php',
			'class-' . basename( $module_path ) . '.php'
		];

		foreach ( $required_files as $file ) {
			if ( ! file_exists( $module_path . '/' . $file ) ) {
				$this->add_security_issue( 'missing_file', sprintf( 
					'Required file missing: %s', 
					$file
				) );
			}
		}
	}

	/**
	 * Add security issue
	 *
	 * @param  string $type
	 * @param  string $message
	 * @return void
	 */
	private function add_security_issue( string $type, string $message ): void {
		$this->security_issues[] = [
			'type' 		=> $type,
			'message' 	=> $message,
			'timestamp' => current_time( 'mysql' )
		];
	}

	/**
	 * Log security issues
	 *
	 * @param  string $module_path
	 * @return void
	 */
	private function log_security_issues( string $module_path ): void {
		$module_name = basename( $module_path );
		
		error_log( sprintf( 
			'WeCodeArt Module Security: Issues found in module "%s": %s', 
			$module_name, 
			json_encode( $this->security_issues )
		) );

		// Store in transient for admin display
		$transient_key = 'wecodeart_module_security_' . sanitize_title( $module_name );
		set_transient( $transient_key, $this->security_issues, HOUR_IN_SECONDS );
	}

	/**
	 * Get security issues for a module
	 *
	 * @param  string $module_name
	 * @return array
	 */
	public function get_security_issues( string $module_name ): array {
		$transient_key = 'wecodeart_module_security_' . sanitize_title( $module_name );
		return get_transient( $transient_key ) ?: [];
	}

	/**
	 * Get validation results
	 *
	 * @return array
	 */
	public function get_validation_results(): array {
		return $this->validation_results;
	}

	/**
	 * Clear security issues for a module
	 *
	 * @param  string $module_name
	 * @return void
	 */
	public function clear_security_issues( string $module_name ): void {
		$transient_key = 'wecodeart_module_security_' . sanitize_title( $module_name );
		delete_transient( $transient_key );
	}
} 