<?php
/**
 * Tools Page (Helm → Tools).
 *
 * Production/portability utilities for site owners and agencies:
 *   - Export all Helm settings to a JSON file.
 *   - Import settings from a JSON file (with a safety confirmation).
 *   - Run all scans now (Link Health rescan).
 *   - Clear all Helm caches (transients).
 *   - Reset the plugin settings to defaults (module toggles back to default).
 *
 * Every action is capability-checked and nonce-protected. Import validates the
 * payload shape and only writes recognised keys, so a malformed or hostile
 * file can't inject arbitrary options.
 *
 * This is core infrastructure (registered by Plugin), not a toggleable module.
 *
 * @package Platform\Helm\Admin
 */

declare( strict_types = 1 );

namespace Platform\Helm\Admin;

use Platform\Helm\Core\Settings;
use Platform\Helm\Core\Ui;

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

final class ToolsPage {

	public const PAGE_SLUG   = 'platform-helm-tools';
	public const PARENT_SLUG = 'platform-helm';
	private const CAPABILITY  = 'manage_options';

	private const EXPORT_ACTION = 'platform_helm_export_settings';
	private const IMPORT_ACTION = 'platform_helm_import_settings';
	private const TOOL_ACTION    = 'platform_helm_run_tool';

	public function __construct( private Settings $settings ) {}

	public function register_hooks(): void {
		add_action( 'admin_menu', [ $this, 'register_menu' ], 60 );
		add_action( 'admin_post_' . self::EXPORT_ACTION, [ $this, 'handle_export' ] );
		add_action( 'admin_post_' . self::IMPORT_ACTION, [ $this, 'handle_import' ] );
		add_action( 'admin_post_' . self::TOOL_ACTION, [ $this, 'handle_tool' ] );
	}

	public function register_menu(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			return;
		}
		add_submenu_page(
			self::PARENT_SLUG,
			__( 'Tools', 'platform-helm' ),
			__( 'Tools', 'platform-helm' ),
			self::CAPABILITY,
			self::PAGE_SLUG,
			[ $this, 'render' ]
		);
	}

	/* ===================================================================== *
	 * EXPORT
	 * ===================================================================== */

	public function handle_export(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			wp_die( esc_html__( 'Permission denied.', 'platform-helm' ) );
		}
		check_admin_referer( self::EXPORT_ACTION );

		$payload = [
			'_meta'    => [
				'plugin'      => 'platform-helm',
				'version'     => PLATFORM_HELM_VERSION,
				'exported_at' => gmdate( 'c' ),
				'site'        => home_url(),
			],
			'settings' => $this->settings->all(),
			// Per-module standalone option (suggester) included for completeness.
			'link_suggester' => get_option( 'platform_helm_link_suggester', [] ),
			'role_menu_hidden' => get_option( 'platform_helm_role_menu_hidden', [] ),
		];

		$json     = wp_json_encode( $payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
		$filename = 'platform-helm-settings-' . gmdate( 'Y-m-d-His' ) . '.json';

		nocache_headers();
		header( 'Content-Type: application/json; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename=' . $filename );
		echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		exit;
	}

	/* ===================================================================== *
	 * IMPORT
	 * ===================================================================== */

	public function handle_import(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			wp_die( esc_html__( 'Permission denied.', 'platform-helm' ) );
		}
		check_admin_referer( self::IMPORT_ACTION );

		$redirect = admin_url( 'admin.php?page=' . self::PAGE_SLUG );

		if ( empty( $_FILES['helm_import_file']['tmp_name'] ) || ! is_uploaded_file( $_FILES['helm_import_file']['tmp_name'] ) ) {
			wp_safe_redirect( add_query_arg( 'helm_msg', 'import_nofile', $redirect ) );
			exit;
		}

		// Read and decode.
		$raw = file_get_contents( $_FILES['helm_import_file']['tmp_name'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions
		$data = json_decode( (string) $raw, true );

		if ( ! is_array( $data ) || empty( $data['_meta']['plugin'] ) || 'platform-helm' !== $data['_meta']['plugin'] ) {
			wp_safe_redirect( add_query_arg( 'helm_msg', 'import_invalid', $redirect ) );
			exit;
		}

		// Apply only recognised pieces, each validated.
		if ( isset( $data['settings'] ) && is_array( $data['settings'] ) ) {
			$clean = $this->sanitise_settings_payload( $data['settings'] );
			update_option( Settings::OPTION_KEY, $clean );
			$this->settings->flush_cache();
		}
		if ( isset( $data['link_suggester'] ) && is_array( $data['link_suggester'] ) ) {
			update_option( 'platform_helm_link_suggester', $data['link_suggester'], false );
		}
		if ( isset( $data['role_menu_hidden'] ) && is_array( $data['role_menu_hidden'] ) ) {
			update_option( 'platform_helm_role_menu_hidden', $data['role_menu_hidden'], false );
		}

		wp_safe_redirect( add_query_arg( 'helm_msg', 'import_ok', $redirect ) );
		exit;
	}

	/**
	 * Whitelist + cast the settings array on import. Module toggles (module_*)
	 * and known preference keys only; everything else is dropped, so a crafted
	 * file can't smuggle in arbitrary option data.
	 *
	 * @param array<string,mixed> $in
	 * @return array<string,mixed>
	 */
	private function sanitise_settings_payload( array $in ): array {
		$out = [];
		foreach ( $in as $key => $value ) {
			if ( 0 === strpos( (string) $key, 'module_' ) ) {
				$out[ $key ] = (bool) $value;
			}
		}
		$bool_prefs = [ 'pd_clean_mode', 'health_alert_email', 'remove_data_on_uninstall' ];
		foreach ( $bool_prefs as $k ) {
			if ( array_key_exists( $k, $in ) ) {
				$out[ $k ] = (bool) $in[ $k ];
			}
		}
		if ( isset( $in['activity_retention_days'] ) ) {
			$out['activity_retention_days'] = max( 0, min( 3650, (int) $in['activity_retention_days'] ) );
		}
		return $out;
	}

	/* ===================================================================== *
	 * MAINTENANCE TOOLS
	 * ===================================================================== */

	public function handle_tool(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			wp_die( esc_html__( 'Permission denied.', 'platform-helm' ) );
		}
		check_admin_referer( self::TOOL_ACTION );

		$tool     = isset( $_POST['tool'] ) ? sanitize_key( wp_unslash( (string) $_POST['tool'] ) ) : '';
		$redirect = admin_url( 'admin.php?page=' . self::PAGE_SLUG );
		$msg      = 'tool_done';

		switch ( $tool ) {
			case 'run_scans':
				// Force a fresh Link Health scan if that class is available.
				if ( class_exists( '\Platform\Helm\Modules\Link_Health\HealthAnalyzer' ) ) {
					( new \Platform\Helm\Modules\Link_Health\HealthAnalyzer() )->get_report( true );
				}
				$msg = 'scans_done';
				break;

			case 'clear_caches':
				\Platform\Helm\Core\CacheManager::clear_all();
				$msg = 'caches_cleared';
				break;

			case 'reset_settings':
				delete_option( Settings::OPTION_KEY );
				$this->settings->flush_cache();
				$msg = 'settings_reset';
				break;
		}

		wp_safe_redirect( add_query_arg( 'helm_msg', $msg, $redirect ) );
		exit;
	}

	/* ===================================================================== *
	 * RENDER
	 * ===================================================================== */

	public function render(): void {
		if ( ! current_user_can( self::CAPABILITY ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'platform-helm' ) );
		}

		Ui::open_page(
			__( 'Tools', 'platform-helm' ),
			__( 'Export / import settings, maintenance, and diagnostics.', 'platform-helm' )
		);
		$this->maybe_notice();

		echo '<div class="tool-grid">';

		// Export.
		$this->tool_card_open( 'ti-download', 'accent', __( 'Export Settings', 'platform-helm' ), __( 'Download your complete Helm configuration as a JSON file — back up before a migration, or copy to another site.', 'platform-helm' ) );
		printf(
			'<a class="btn btn-secondary" style="width:100%%;margin-top:auto" href="%s"><i class="ti ti-download" aria-hidden="true"></i> %s</a>',
			esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=' . self::EXPORT_ACTION ), self::EXPORT_ACTION ) ),
			esc_html__( 'Download settings.json', 'platform-helm' )
		);
		$this->tool_card_close();

		// Import.
		$this->tool_card_open( 'ti-upload', 'success', __( 'Import Settings', 'platform-helm' ), __( 'Restore configuration from a previously exported JSON file. Existing settings are overwritten.', 'platform-helm' ) );
		echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" enctype="multipart/form-data" style="margin-top:auto">';
		wp_nonce_field( self::IMPORT_ACTION );
		echo '<input type="hidden" name="action" value="' . esc_attr( self::IMPORT_ACTION ) . '">';
		echo '<input type="file" name="helm_import_file" accept="application/json,.json" required class="field-input" style="margin-bottom:10px">';
		printf(
			'<button type="submit" class="btn btn-ghost" style="width:100%%" onclick="return confirm(\'%s\')"><i class="ti ti-upload" aria-hidden="true"></i> %s</button>',
			esc_js( __( 'Importing will overwrite your current Helm settings. Continue?', 'platform-helm' ) ),
			esc_html__( 'Import settings', 'platform-helm' )
		);
		echo '</form>';
		$this->tool_card_close();

		// Run scans.
		$this->tool_card_form( 'ti-refresh', 'accent', __( 'Run All Scans', 'platform-helm' ), __( 'Force a fresh Link Health scan now instead of waiting for the schedule.', 'platform-helm' ), 'run_scans', __( 'Run scans now', 'platform-helm' ), 'btn-secondary', 'ti-player-play' );

		// Clear caches.
		$this->tool_card_form( 'ti-database-off', 'warning', __( 'Clear Cached Data', 'platform-helm' ), __( "Clears Helm's transient caches and temporary scan data. Settings and logs are untouched.", 'platform-helm' ), 'clear_caches', __( 'Clear cache', 'platform-helm' ), 'btn-ghost', 'ti-trash' );

		// Reset (destructive).
		$this->tool_card_open( 'ti-alert-triangle', 'danger', __( 'Reset All Settings', 'platform-helm' ), __( 'Resets all module toggles and preferences to their defaults. Your content and logs are not touched.', 'platform-helm' ) );
		echo '<div class="notice notice-danger" style="margin-bottom:10px"><strong>' . esc_html__( 'Warning:', 'platform-helm' ) . '</strong> ' . esc_html__( 'Irreversible unless you have an export backup.', 'platform-helm' ) . '</div>';
		echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" style="margin-top:auto">';
		wp_nonce_field( self::TOOL_ACTION );
		echo '<input type="hidden" name="action" value="' . esc_attr( self::TOOL_ACTION ) . '">';
		echo '<input type="hidden" name="tool" value="reset_settings">';
		printf(
			'<button type="submit" class="btn btn-danger-ghost" style="width:100%%" onclick="return confirm(\'%s\')"><i class="ti ti-refresh-alert" aria-hidden="true"></i> %s</button>',
			esc_js( __( 'This resets all module toggles and preferences to defaults. Continue?', 'platform-helm' ) ),
			esc_html__( 'Reset to defaults', 'platform-helm' )
		);
		echo '</form>';
		$this->tool_card_close();

		// Diagnostics — live environment, checked against requirements.
		$this->render_diagnostics_card();

		echo '</div>';
		Ui::close_page();
	}

	/**
	 * Open a tool card: icon chip + name + description. Pair with tool_card_close().
	 */
	private function tool_card_open( string $icon, string $tone, string $name, string $desc ): void {
		$tones = [
			'accent'  => 'background:var(--accent-tint);color:var(--accent-hover)',
			'success' => 'background:var(--success-tint);color:var(--success)',
			'warning' => 'background:var(--warning-tint);color:var(--warning)',
			'danger'  => 'background:var(--danger-tint);color:var(--danger)',
			'muted'   => 'background:var(--bg-secondary);color:var(--text-muted)',
		];
		$style = $tones[ $tone ] ?? $tones['accent'];
		echo '<div class="tool-card">';
		echo '<div class="tool-card-header"><div class="tool-icon" style="' . esc_attr( $style ) . '"><i class="ti ' . esc_attr( $icon ) . '" aria-hidden="true"></i></div><div><p class="tool-name">' . esc_html( $name ) . '</p></div></div>';
		echo '<p class="tool-desc">' . esc_html( $desc ) . '</p>';
	}

	private function tool_card_close(): void {
		echo '</div>';
	}

	/**
	 * A complete tool card whose action is a single nonce-protected POST.
	 */
	private function tool_card_form( string $icon, string $tone, string $name, string $desc, string $tool, string $label, string $btn_class, string $btn_icon ): void {
		$this->tool_card_open( $icon, $tone, $name, $desc );
		echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" style="margin-top:auto">';
		wp_nonce_field( self::TOOL_ACTION );
		echo '<input type="hidden" name="action" value="' . esc_attr( self::TOOL_ACTION ) . '">';
		echo '<input type="hidden" name="tool" value="' . esc_attr( $tool ) . '">';
		printf(
			'<button type="submit" class="btn %1$s" style="width:100%%"><i class="ti %2$s" aria-hidden="true"></i> %3$s</button>',
			esc_attr( $btn_class ),
			esc_attr( $btn_icon ),
			esc_html( $label )
		);
		echo '</form>';
		$this->tool_card_close();
	}

	/**
	 * Diagnostics card — real, live environment values checked against Helm's
	 * minimum requirements.
	 */
	private function render_diagnostics_card(): void {
		global $wpdb;
		$wp_version = get_bloginfo( 'version' );
		$db_version = (string) $wpdb->db_version();

		$rows = [
			[ 'PHP ' . PHP_VERSION, version_compare( PHP_VERSION, '8.0', '>=' ) ],
			[ 'MySQL ' . $db_version, version_compare( $db_version, '5.7', '>=' ) ],
			[ 'WordPress ' . $wp_version, version_compare( $wp_version, '6.0', '>=' ) ],
			[ 'Platform Helm ' . PLATFORM_HELM_VERSION, true ],
		];

		$this->tool_card_open( 'ti-bug', 'muted', __( 'Diagnostics', 'platform-helm' ), __( 'Your environment, checked against Helm’s requirements.', 'platform-helm' ) );
		echo '<div style="margin-top:auto;background:var(--bg-secondary);border-radius:var(--r-md);padding:10px 12px;font-family:var(--font-mono);font-size:11px;color:var(--text-secondary);line-height:1.9">';
		foreach ( $rows as $r ) {
			$ok = $r[1]
				? '<span style="color:var(--success)">&#10003;</span>'
				: '<span style="color:var(--danger)">&#10007;</span>';
			echo esc_html( (string) $r[0] ) . ' &middot; ' . $ok . '<br>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}
		echo '</div>';
		$this->tool_card_close();
	}

	private function maybe_notice(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$msg = isset( $_GET['helm_msg'] ) ? sanitize_key( wp_unslash( (string) $_GET['helm_msg'] ) ) : '';
		if ( '' === $msg ) {
			return;
		}
		$map = [
			'import_ok'      => [ 'success', __( 'Settings imported successfully.', 'platform-helm' ) ],
			'import_invalid' => [ 'danger',  __( 'That file is not a valid Platform Helm settings export.', 'platform-helm' ) ],
			'import_nofile'  => [ 'danger',  __( 'No file was uploaded.', 'platform-helm' ) ],
			'scans_done'     => [ 'success', __( 'All scans have been run.', 'platform-helm' ) ],
			'caches_cleared' => [ 'success', __( 'All Helm caches cleared.', 'platform-helm' ) ],
			'settings_reset' => [ 'success', __( 'Settings reset to defaults.', 'platform-helm' ) ],
			'tool_done'      => [ 'success', __( 'Done.', 'platform-helm' ) ],
		];
		if ( ! isset( $map[ $msg ] ) ) {
			return;
		}
		[ $type, $text ] = $map[ $msg ];
		Ui::notice( esc_html( $text ), $type );
	}
}
