<?php
/**
 * Admin AJAX handlers for the WP Config Editor module.
 *
 * @package WP_PowerSuite\Core\Http\Controllers
 * @since 1.0.0
 */

namespace WP_PowerSuite\Core\Http\Controllers;

use WP_PowerSuite\Core\Http\AjaxRouter;
use WP_PowerSuite\Core\OptionStoreModuleSettingsRepository;
use WP_PowerSuite\Core\WpConfigAuditLog;
use WP_PowerSuite\Core\WpConfigHelper;

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

final class WpConfigEditorController {

	private static ?self $instance = null;

	public static function getInstance(): self {
		if ( self::$instance === null ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	public static function register(): void {
		if ( ! OptionStoreModuleSettingsRepository::isModuleEnabled( 'wp-config-editor' ) ) {
			return;
		}

		$controller = self::getInstance();
		$capability = WpConfigHelper::requiredManageCapability();

		AjaxRouter::registerAdminAction( 'wp_powersuite_config_editor_get', [ $controller, 'getConfig' ], $capability );
		AjaxRouter::registerAdminAction( 'wp_powersuite_config_editor_save', [ $controller, 'saveConfig' ], $capability );
		AjaxRouter::registerAdminAction( 'wp_powersuite_config_editor_backup', [ $controller, 'backupConfig' ], $capability );
	}

	/**
	 * Module PHP files are not autoloaded during admin AJAX; require before use.
	 */
	private function getEditorModule(): \WPConfigEditor\Module {
		if ( ! class_exists( '\WPConfigEditor\Module', false ) && defined( 'WP_POWERSUITE_MODULES_DIR' ) ) {
			$module_file = WP_POWERSUITE_MODULES_DIR . 'wp-config-editor' . DIRECTORY_SEPARATOR . 'module.php';
			if ( is_readable( $module_file ) ) {
				require_once $module_file;
			}
		}

		if ( ! class_exists( '\WPConfigEditor\Module', false ) ) {
			wp_send_json_error(
				[
					'message' => __( 'WP Config Editor module could not be loaded.', 'wp-powersuite' ),
					'code'    => 'module_not_found',
				]
			);
		}

		return new \WPConfigEditor\Module();
	}

	private function rejectIfCannotEditWpConfig(): void {
		if ( WpConfigHelper::canManageWpConfig() ) {
			return;
		}

		wp_send_json_error(
			[
				'message' => __( 'You do not have permission to read or edit wp-config.php.', 'wp-powersuite' ),
				'code'    => 'insufficient_permissions',
			]
		);
	}

	public function getConfig(): void {
		$this->rejectIfCannotEditWpConfig();

		$mod = $this->getEditorModule();
		if ( ! $mod->isEnabled() ) {
			wp_send_json_error( [ 'message' => __( 'Module is not enabled.', 'wp-powersuite' ) ] );
		}

		$content = $mod->getConfigContent();
		if ( $content === false ) {
			wp_send_json_error( [ 'message' => __( 'Could not read wp-config.php.', 'wp-powersuite' ) ] );
		}

		$reveal = isset( $_POST['reveal_secrets'] ) && sanitize_key( wp_unslash( $_POST['reveal_secrets'] ) ) === '1';
		if ( $reveal ) {
			WpConfigAuditLog::log( 'wp-config-editor', 'reveal_secrets', __( 'Revealed wp-config.php secrets in the editor.', 'wp-powersuite' ) );
			wp_send_json_success(
				[
					'content' => $content,
					'masked'  => false,
				]
			);
		}

		wp_send_json_success(
			[
				'content' => WpConfigHelper::maskSecrets( $content ),
				'masked'  => true,
			]
		);
	}

	public function saveConfig(): void {
		$this->rejectIfCannotEditWpConfig();

		$content = isset( $_POST['content'] ) ? wp_unslash( $_POST['content'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		if ( ! is_string( $content ) ) {
			wp_send_json_error( [ 'message' => __( 'Invalid content.', 'wp-powersuite' ) ] );
		}
		if ( strlen( $content ) > 512 * 1024 ) {
			wp_send_json_error( [ 'message' => __( 'Content too large. Maximum 512 KB.', 'wp-powersuite' ) ] );
		}

		$mod = $this->getEditorModule();
		if ( ! $mod->isEnabled() ) {
			wp_send_json_error( [ 'message' => __( 'Module is not enabled.', 'wp-powersuite' ) ] );
		}
		if ( ! $mod->isConfigWritable() ) {
			wp_send_json_error( [ 'message' => __( 'wp-config.php is not writable.', 'wp-powersuite' ) ] );
		}

		$config_path = $mod->getConfigPath();
		if ( ! $config_path ) {
			wp_send_json_error( [ 'message' => __( 'wp-config.php not found.', 'wp-powersuite' ) ] );
		}

		$original = $mod->getConfigContent();
		if ( $original !== false ) {
			$content = WpConfigHelper::mergeMaskedSecrets( $content, $original );
		}

		$validation = WpConfigHelper::validatePhpSyntax( $content );
		if ( ! $validation['valid'] ) {
			wp_send_json_error( [ 'message' => $validation['message'] ] );
		}

		$backup = $mod->createBackup();
		if ( $backup === false ) {
			wp_send_json_error( [ 'message' => __( 'Could not create backup. Save aborted.', 'wp-powersuite' ) ] );
		}

		$write = $mod->writeConfigWithMessage( $content );
		if ( ! $write['success'] ) {
			WpConfigHelper::restoreFromBackup( (string) $backup, $config_path );
			$message = $write['message'] !== ''
				? $write['message'] . ' ' . __( 'Previous config was restored from backup.', 'wp-powersuite' )
				: __( 'Could not write wp-config.php. Previous config was restored from backup.', 'wp-powersuite' );
			wp_send_json_error( [ 'message' => $message ] );
		}

		WpConfigAuditLog::log( 'wp-config-editor', 'save', __( 'Saved wp-config.php from the dashboard editor.', 'wp-powersuite' ) );

		wp_send_json_success( [ 'message' => __( 'Config saved.', 'wp-powersuite' ) ] );
	}

	public function backupConfig(): void {
		$this->rejectIfCannotEditWpConfig();

		$mod = $this->getEditorModule();
		if ( ! $mod->isEnabled() ) {
			wp_send_json_error( [ 'message' => __( 'Module is not enabled.', 'wp-powersuite' ) ] );
		}

		$backup = $mod->createBackup();
		if ( $backup === false ) {
			wp_send_json_error( [ 'message' => __( 'Could not create backup.', 'wp-powersuite' ) ] );
		}

		WpConfigAuditLog::log(
			'wp-config-editor',
			'backup',
			sprintf(
				/* translators: %s: backup filename */
				__( 'Created wp-config.php backup: %s', 'wp-powersuite' ),
				basename( (string) $backup )
			)
		);

		wp_send_json_success(
			[
				'message' => sprintf(
					/* translators: %s: string value. */
					__( 'Backup created: %s', 'wp-powersuite' ),
					basename( (string) $backup )
				),
				'backup'  => basename( (string) $backup ),
			]
		);
	}
}

