<?php

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

final class WpironFilesDirectoryProtection {

	private WpironHelper $helpers;

	const OPTION_NAME = 'wpironis_options';
	const BLOCKED_EXTENSIONS = [
		'php',
		'php3',
		'php4',
		'php5',
		'php7',
		'phtml',
		'cgi',
		'pl',
		'py',
		'jsp',
		'asp',
		'htm',
		'shtml',
		'sh',
		'phar'
	];

	public function __construct(WpironHelper $helper) {
		$this->helpers = $helper;
	}

	public function handlePhpUploadToggle($enabled) {
		$options = $this->helpers->wpironis_getOption( self::OPTION_NAME );
		$options['wpironis_block_php_uploads'] = $enabled ? 1 : 0;
		$updated = $this->helpers->wpironis_updateOption( self::OPTION_NAME, $options );

		if ( $enabled ) {
			$this->wpironis_create_upload_protection();
		} else {
			$this->wpironis_remove_upload_protection();
		}

		if ( $updated ) {
			wp_send_json_success( array(
				'message' => __( 'PHP file upload blocking setting updated successfully', 'iron-security' ),
				'enabled' => $enabled,
				'options' => $options
			) );
		} else {
			$current_options = get_option( 'wpironis_options' );
			if ( isset( $current_options['wpironis_block_php_uploads'] ) &&
			     $current_options['wpironis_block_php_uploads'] === ( $enabled ? 1 : 0 ) ) {
				wp_send_json_success( array(
					'message' => __( 'PHP file upload blocking setting is already set to this value', 'iron-security' ),
					'enabled' => $enabled,
					'options' => $current_options
				) );
			} else {
				wp_send_json_error( __( 'Failed to update PHP file upload blocking setting', 'iron-security' ) );
			}
		}

	}

	private function wpironis_create_upload_protection() {
		$upload_dir    = wp_upload_dir();
		$htaccess_path = $upload_dir['basedir'] . '/.htaccess';

		$rules = "
# Iron Security
Options -Indexes
<IfModule mod_php7.c>
    php_flag engine off
</IfModule>
<IfModule mod_php.c>
    php_flag engine off
</IfModule>
<FilesMatch '\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|old|mdb|json)$'>
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Deny from all
  </IfModule>
</FilesMatch>
<FilesMatch '\.php$'>
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Deny from all
  </IfModule>
</FilesMatch>
# END Iron Security
";

		// Initialize WP_Filesystem
		global $wp_filesystem;
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		WP_Filesystem();

		if ( ! $wp_filesystem->exists( $htaccess_path ) || $wp_filesystem->is_writable( $htaccess_path ) ) {
			$wp_filesystem->put_contents( $htaccess_path, $rules, FS_CHMOD_FILE );
		}

		$index_path = $upload_dir['basedir'] . '/index.php';
		if ( ! $wp_filesystem->exists( $index_path ) ) {
			$wp_filesystem->put_contents( $index_path, '<?php // Silence is golden', FS_CHMOD_FILE );
		}
	}

	private function wpironis_remove_upload_protection() {
		$upload_dir    = wp_upload_dir();
		$htaccess_path = $upload_dir['basedir'] . '/.htaccess';

		// Initialize WP_Filesystem
		global $wp_filesystem;
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		WP_Filesystem();

		if ( $wp_filesystem->exists( $htaccess_path ) ) {
			$wp_filesystem->delete( $htaccess_path );
		}
	}

	public function wpironis_preventProgrammableFileUploads($file) {
		$options = $this->helpers->wpironis_getOption( self::OPTION_NAME );

		if ( ! isset( $options['wpironis_block_php_uploads'] ) || $options['wpironis_block_php_uploads'] !== 1 ) {
			return $file;
		}

		if ( ! isset( $file['name'] ) || empty( $file['name'] ) || ! is_string( $file['name'] ) ) {
			$file['error'] = __( 'Invalid file name detected. Upload blocked.', 'iron-security' );

			return $file;
		}

		$file_path = $file['name'];
		$extension = strtolower( pathinfo( $file_path, PATHINFO_EXTENSION ) ?: '' );


		if ( in_array( $extension, self::BLOCKED_EXTENSIONS, true ) ) {
			$file['error'] = sprintf(
				/* translators: %s: Name of a extension */
				__( 'Upload of PHP and executable files is not allowed for security reasons. Blocked extension: .%s', 'iron-security' ),
				$extension
			);

			return $file;
		}


		$all_extensions = explode( '.', $file_path );
		if ( count( $all_extensions ) > 2 ) {
			foreach ( self::BLOCKED_EXTENSIONS as $blocked_ext ) {
				if ( in_array( $blocked_ext, $all_extensions, true ) ) {
					$file['error'] = __( 'Files with multiple extensions are not allowed for security reasons.', 'iron-security' );
					break;
				}
			}
		}

		return $file;
	}

	public function handleDirectFileAccessToggle($enabled) {
		$options = $this->helpers->wpironis_getOption( self::OPTION_NAME );
		$options['wpironis_prevent_direct_access'] = $enabled ? 1 : 0;
		$updated = $this->helpers->wpironis_updateOption( self::OPTION_NAME, $options );

		if ( $enabled ) {
			$this->wpironis_create_file_protection();
		} else {
			$this->wpironis_remove_file_protection();
		}

		if ( $updated ) {
			wp_send_json_success( array(
				'message' => __( 'Direct file access protection setting updated successfully', 'iron-security' ),
				'enabled' => $enabled,
				'options' => $options
			) );
		} else {
			$current_options = get_option( 'wpironis_options' );
			if ( isset( $current_options['wpironis_prevent_direct_access'] ) &&
			     $current_options['wpironis_prevent_direct_access'] === ( $enabled ? 1 : 0 ) ) {
				wp_send_json_success( array(
					'message' => __( 'Direct file access protection setting is already set to this value',
						'iron-security' ),
					'enabled' => $enabled,
					'options' => $current_options
				) );
			} else {
				wp_send_json_error( __( 'Failed to update direct file access protection setting', 'iron-security' ) );
			}
		}

	}

	private function wpironis_create_file_protection() {
		$root_htaccess_path = ABSPATH . '.htaccess';

		$rules = "
# Iron Security
<FilesMatch '^(wp-config\.php|php\.ini|php5\.ini|install\.php|wp-config-sample\.php|readme\.html|license\.txt|debug\.log)$'>
    deny from all
</FilesMatch>

<Files .htaccess>
  Require all denied
</Files>

<Files wp-config.php>
  Require all denied
</Files>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

Options -Indexes

<IfModule mod_rewrite.c>
  RewriteRule ^wp-admin/includes/ - [F,L]
  RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
  RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
  RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
# END Iron Security
";

		// Initialize WP_Filesystem
		global $wp_filesystem;
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		WP_Filesystem();

		if ( ! $wp_filesystem->exists( $root_htaccess_path ) || $wp_filesystem->is_writable( $root_htaccess_path ) ) {
			$existing_content = $wp_filesystem->exists( $root_htaccess_path ) ? $wp_filesystem->get_contents( $root_htaccess_path ) : '';

			if ( strpos( $existing_content, 'Iron Security - Prevent Direct File Access' ) === false ) {
				if ( strpos( $existing_content, '# END WordPress' ) !== false ) {
					$existing_content = str_replace( '# END WordPress',
						"# END WordPress\n\n" . $rules,
						$existing_content );
				} else {
					$existing_content .= "\n" . $rules;
				}

				$wp_filesystem->put_contents( $root_htaccess_path, $existing_content, FS_CHMOD_FILE );
			}
		}

		$content_htaccess_path = WP_CONTENT_DIR . '/.htaccess';
		$content_rules         = "
# Iron Security
Options -Indexes
<FilesMatch '\.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|old|mdb|json|config)$'>
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Deny from all
  </IfModule>
</FilesMatch>
# END Iron Security
";

		if ( ! $wp_filesystem->exists( $content_htaccess_path ) || $wp_filesystem->is_writable( $content_htaccess_path ) ) {
			$wp_filesystem->put_contents( $content_htaccess_path, $content_rules, FS_CHMOD_FILE );
		}
	}

	public function wpironis_remove_file_protection() {
		$root_htaccess_path    = ABSPATH . '.htaccess';
		$content_htaccess_path = WP_CONTENT_DIR . '/.htaccess';
		$pattern               = '/# Iron Security.*?# END Iron Security\s*/s';

		// Initialize WP_Filesystem
		global $wp_filesystem;
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		WP_Filesystem();

		if ( $wp_filesystem->exists( $root_htaccess_path ) && $wp_filesystem->is_writable( $root_htaccess_path ) ) {
			$content = $wp_filesystem->get_contents( $root_htaccess_path );
			$new_content = preg_replace( $pattern, '', $content );

			if ( $new_content !== null ) {
				$wp_filesystem->put_contents( $root_htaccess_path, $new_content, FS_CHMOD_FILE );
			}
		}

		if ( $wp_filesystem->exists( $content_htaccess_path ) && $wp_filesystem->is_writable( $content_htaccess_path ) ) {
			$content = $wp_filesystem->get_contents( $content_htaccess_path );
			$new_content = preg_replace( $pattern, '', $content );

			if ( $new_content !== null ) {
				$wp_filesystem->put_contents( $content_htaccess_path, $new_content, FS_CHMOD_FILE );
			}
		}
	}

}