<?php
/**
 * Settings Page — Modules submenu.
 *
 * Renders the module on/off toggles and a single plugin-wide preference:
 * whether to remove all data on uninstall (off by default — see uninstall.php).
 * Lives at `admin.php?page=platform-helm-modules` under the top-level Helm menu.
 *
 * SECURITY: gated by `manage_options`; option writes go through the Settings
 * API with a sanitize callback, so every value is validated server-side.
 *
 * @package Platform\Helm\Admin
 */

declare( strict_types = 1 );

namespace Platform\Helm\Admin;

use Platform\Helm\Contracts\ModuleInterface;
use Platform\Helm\Core\Licensing;
use Platform\Helm\Core\ModuleRegistry;
use Platform\Helm\Core\Settings;
use Platform\Helm\Core\Ui;

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

final class SettingsPage {

	public const PAGE_SLUG       = 'platform-helm-modules';
	public const PARENT_SLUG     = 'platform-helm';
	public const SETTING_SECTION = 'platform_helm_modules_section';
	public const SETTING_PREFS   = 'platform_helm_prefs_section';
	public const SETTING_GROUP   = 'platform_helm_settings_group';

	private const CAPABILITY = 'manage_options';

	/** Preference key controlling destructive uninstall. */
	public const PREF_REMOVE_DATA = 'remove_data_on_uninstall';

	public function __construct(
		private Settings $settings,
		private ModuleRegistry $registry
	) {}

	public function register_hooks(): void {
		// Priority 10 — after DashboardPage (priority 9) registers the parent.
		add_action( 'admin_menu', [ $this, 'register_menu' ], 10 );
		add_action( 'admin_init', [ $this, 'register_settings' ] );
		add_action( 'update_option_' . Settings::OPTION_KEY, [ $this, 'on_settings_saved' ], 10, 0 );
	}

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

	public function register_settings(): void {
		register_setting(
			self::SETTING_GROUP,
			Settings::OPTION_KEY,
			[
				'type'              => 'array',
				'sanitize_callback' => [ $this, 'sanitize_settings' ],
				'default'           => [],
			]
		);

		// --- Modules section ---
		add_settings_section(
			self::SETTING_SECTION,
			__( 'Modules', 'platform-helm' ),
			function () {
				echo '<p>' . esc_html__( 'Enable or disable individual modules. Disabled modules register no hooks and have zero runtime cost.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG
		);

		foreach ( $this->registry->all() as $module ) {
			add_settings_field(
				'module_' . $module->id(),
				esc_html( $module->name() ),
				function () use ( $module ) {
					$key     = 'module_' . $module->id();
					$option  = Settings::OPTION_KEY;
					$enabled = $this->settings->is_module_enabled( $module->id(), $module->default_enabled() );
					printf(
						'<label><input type="checkbox" name="%s[%s]" value="1" %s> %s</label>',
						esc_attr( $option ),
						esc_attr( $key ),
						checked( $enabled, true, false ),
						esc_html__( 'Enabled', 'platform-helm' )
					);
					if ( '' !== $module->description() ) {
						echo '<p class="description">' . esc_html( $module->description() ) . '</p>';
					}
				},
				self::PAGE_SLUG,
				self::SETTING_SECTION
			);
		}

		// --- Module preferences section (Persona Dashboards + Link Health) ---
		add_settings_section(
			'platform_helm_module_prefs',
			__( 'Module preferences', 'platform-helm' ),
			function () {
				echo '<p>' . esc_html__( 'Fine-tune individual module behaviour. Each setting only applies when its module is enabled.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG
		);

		add_settings_field(
			'pd_clean_mode',
			esc_html__( 'Clean dashboard mode', 'platform-helm' ),
			function () {
				$option  = Settings::OPTION_KEY;
				$enabled = (bool) $this->settings->get( 'pd_clean_mode', false );
				printf(
					'<label><input type="checkbox" name="%s[%s]" value="1" %s> %s</label>',
					esc_attr( $option ),
					esc_attr( 'pd_clean_mode' ),
					checked( $enabled, true, false ),
					esc_html__( 'Remove the default WordPress dashboard widgets for users with a Helm persona', 'platform-helm' )
				);
				echo '<p class="description">' . esc_html__( 'Off by default. When on, the noisy native widgets (Activity, At a Glance, Quick Draft, Events & News, etc.) are hidden so only your Helm widgets remain. Third-party plugin widgets are never touched.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG,
			'platform_helm_module_prefs'
		);

		add_settings_field(
			'health_alert_email',
			esc_html__( 'Email link-health alerts', 'platform-helm' ),
			function () {
				$option  = Settings::OPTION_KEY;
				$enabled = (bool) $this->settings->get( 'health_alert_email', false );
				printf(
					'<label><input type="checkbox" name="%s[%s]" value="1" %s> %s</label>',
					esc_attr( $option ),
					esc_attr( 'health_alert_email' ),
					checked( $enabled, true, false ),
					esc_html__( 'Email the site admin when the weekly scan finds link health degrading', 'platform-helm' )
				);
				echo '<p class="description">' . esc_html__( 'Off by default. The weekly Internal Link Health scan always shows an in-dashboard notice when orphans or broken links rise; enable this to also receive an email. Requires your site to be able to send mail.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG,
			'platform_helm_module_prefs'
		);

		add_settings_field(
			'activity_retention_days',
			esc_html__( 'Activity log retention', 'platform-helm' ),
			function () {
				$option = Settings::OPTION_KEY;
				$days   = (int) $this->settings->get( 'activity_retention_days', 0 );
				printf(
					'<input type="number" min="0" max="3650" name="%s[%s]" value="%s" class="small-text"> %s',
					esc_attr( $option ),
					esc_attr( 'activity_retention_days' ),
					esc_attr( (string) $days ),
					esc_html__( 'days', 'platform-helm' )
				);
				echo '<p class="description">' . esc_html__( 'Automatically delete activity-log entries older than this many days. Set to 0 to keep entries forever (default). Pruning runs daily.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG,
			'platform_helm_module_prefs'
		);

		// --- Preferences section ---
		add_settings_section(
			self::SETTING_PREFS,
			__( 'Data &amp; Privacy', 'platform-helm' ),
			function () {
				echo '<p>' . esc_html__( 'Platform Helm preserves all of your data on uninstall by default. Enable the option below only if you want a full teardown when you delete the plugin.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG
		);

		add_settings_field(
			self::PREF_REMOVE_DATA,
			esc_html__( 'Remove all data on uninstall', 'platform-helm' ),
			function () {
				$option  = Settings::OPTION_KEY;
				$enabled = (bool) $this->settings->get( self::PREF_REMOVE_DATA, false );
				printf(
					'<label><input type="checkbox" name="%s[%s]" value="1" %s> %s</label>',
					esc_attr( $option ),
					esc_attr( self::PREF_REMOVE_DATA ),
					checked( $enabled, true, false ),
					esc_html__( 'Delete all Platform Helm settings and data when the plugin is deleted', 'platform-helm' )
				);
				echo '<p class="description">' . esc_html__( 'Off by default. When off, deleting the plugin preserves your settings and any saved data, so a reinstall picks up where you left off.', 'platform-helm' ) . '</p>';
			},
			self::PAGE_SLUG,
			self::SETTING_PREFS
		);
	}

	/**
	 * @param mixed $input
	 * @return array<string,mixed>
	 */
	public function sanitize_settings( $input ): array {
		if ( ! is_array( $input ) ) {
			$input = [];
		}
		// Start from existing settings so unrelated keys are preserved.
		$out = $this->settings->all();

		// Module toggles: absent checkbox == false. Locked Pro modules can never
		// be enabled here, no matter what the form posts — server-side enforcement.
		foreach ( $this->registry->all() as $module ) {
			$key         = 'module_' . $module->id();
			$out[ $key ] = Licensing::is_locked( $module->id() ) ? false : ! empty( $input[ $key ] );
		}

		// Uninstall preference.
		$out[ self::PREF_REMOVE_DATA ] = ! empty( $input[ self::PREF_REMOVE_DATA ] );

		// Persona Dashboards: clean-dashboard mode.
		$out['pd_clean_mode'] = ! empty( $input['pd_clean_mode'] );

		// Link Health: email alert opt-in.
		$out['health_alert_email'] = ! empty( $input['health_alert_email'] );

		// Activity Log: retention days (0 = keep forever).
		$out['activity_retention_days'] = isset( $input['activity_retention_days'] )
			? max( 0, min( 3650, (int) $input['activity_retention_days'] ) )
			: 0;

		$this->settings->flush_cache();
		return $out;
	}

	/**
	 * Invalidate the dashboard pulse cache after a save, so the enabled-modules
	 * count reflects the new state on the very next dashboard view.
	 */
	public function on_settings_saved(): void {
		delete_transient( 'platform_helm_pulse_v1' );
	}

	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' ) );
		}

		$save = '<button type="submit" form="ph-modules-form" class="btn btn-primary"><i class="ti ti-device-floppy" aria-hidden="true"></i> ' . esc_html__( 'Save Changes', 'platform-helm' ) . '</button>';
		Ui::open_page(
			__( 'Modules', 'platform-helm' ),
			__( 'Enable the features you need. Disabled modules register no hooks and carry zero runtime cost.', 'platform-helm' ),
			$save
		);
		?>
		<form id="ph-modules-form" method="post" action="options.php">
			<?php settings_fields( self::SETTING_GROUP ); ?>
			<div class="card"><div style="padding:0 20px">
				<?php
				foreach ( $this->registry->all() as $module ) {
					$this->render_module_row( $module );
				}
				?>
			</div></div>
			<?php $this->render_preferences_card(); ?>
			<div style="margin-top:16px">
				<button type="submit" class="btn btn-primary"><i class="ti ti-device-floppy" aria-hidden="true"></i> <?php esc_html_e( 'Save Changes', 'platform-helm' ); ?></button>
			</div>
		</form>
		<?php
		Ui::close_page();
	}

	/**
	 * One module row in the design's toggle-list style.
	 */
	private function render_module_row( ModuleInterface $module ): void {
		$id       = $module->id();
		$locked   = Licensing::is_locked( $id );
		$enabled  = ! $locked && $this->settings->is_module_enabled( $id, $module->default_enabled() );
		$key      = 'module_' . $id;
		$option   = Settings::OPTION_KEY;
		$page_url = $this->module_page_url( $id );

		echo '<div class="module-row' . ( $locked ? ' is-locked' : '' ) . '">';

		// Toggle — disabled and forced off for locked (Pro, unlicensed) modules.
		echo '<div class="module-toggle"><label class="toggle"' . ( $locked ? ' style="opacity:.4;cursor:not-allowed"' : '' ) . '>';
		echo '<input type="checkbox" name="' . esc_attr( $option ) . '[' . esc_attr( $key ) . ']" value="1" ' . checked( $enabled, true, false ) . ( $locked ? ' disabled' : '' ) . '>';
		echo '<span class="toggle-slider"></span></label></div>';

		echo '<div class="module-icon-lg ' . ( $enabled ? 'mi-on-lg' : 'mi-off-lg' ) . '" aria-hidden="true"><i class="ti ' . esc_attr( $locked ? 'ti-lock' : $this->module_icon( $id ) ) . '"></i></div>';
		echo '<div class="module-info">';
		echo '<div class="module-title"' . ( $enabled ? '' : ' style="opacity:.75"' ) . '>' . esc_html( $module->name() );
		if ( $locked ) {
			echo ' <span class="badge" style="background:rgba(245,177,76,.16);color:#9a6a12;border:1px solid rgba(245,177,76,.35)"><i class="ti ti-lock" aria-hidden="true"></i> ' . esc_html__( 'Pro', 'platform-helm' ) . '</span>';
		} elseif ( $enabled ) {
			echo ' <span class="badge badge-info">' . esc_html__( 'Active', 'platform-helm' ) . '</span>';
		} else {
			echo ' <span class="badge badge-neutral">' . esc_html__( 'Off', 'platform-helm' ) . '</span>';
		}
		echo '</div>';
		echo '<p class="module-desc" style="opacity:' . ( $enabled ? '1' : '.65' ) . '">' . esc_html( $module->description() ) . '</p>';
		if ( $locked ) {
			echo '<div class="module-fields"><a class="btn btn-primary btn-sm" href="' . esc_url( Licensing::upgrade_url() ) . '">' . esc_html__( 'Unlock with Pro', 'platform-helm' ) . ' <i class="ti ti-arrow-up-right" aria-hidden="true"></i></a></div>';
		} elseif ( $enabled && '' !== $page_url ) {
			echo '<div class="module-fields"><a class="btn btn-ghost btn-sm" href="' . esc_url( $page_url ) . '">' . esc_html__( 'View module', 'platform-helm' ) . ' <i class="ti ti-arrow-right" aria-hidden="true"></i></a></div>';
		}
		echo '</div>';
		echo '</div>';
	}

	/**
	 * Plugin-wide preferences (real settings) in a design card below the modules.
	 */
	private function render_preferences_card(): void {
		$opt = Settings::OPTION_KEY;
		echo '<div style="margin-top:18px">';
		Ui::card_open( __( 'Preferences', 'platform-helm' ), '', 'ti-adjustments' );
		$this->pref_toggle( $opt, 'pd_clean_mode', __( 'Clean dashboard mode', 'platform-helm' ), __( 'Hide the default WordPress dashboard widgets for users with a Helm persona.', 'platform-helm' ), (bool) $this->settings->get( 'pd_clean_mode', false ) );
		$this->pref_toggle( $opt, 'health_alert_email', __( 'Email link-health alerts', 'platform-helm' ), __( 'Email the site admin when the weekly scan finds link health degrading.', 'platform-helm' ), (bool) $this->settings->get( 'health_alert_email', false ) );
		$this->pref_toggle( $opt, self::PREF_REMOVE_DATA, __( 'Remove all data on uninstall', 'platform-helm' ), __( 'Delete all Helm settings and data when the plugin is deleted. Off by default — your data is preserved.', 'platform-helm' ), (bool) $this->settings->get( self::PREF_REMOVE_DATA, false ) );
		$days = (int) $this->settings->get( 'activity_retention_days', 0 );
		echo '<div class="field-group" style="margin-top:14px;max-width:240px"><label class="field-label" for="ph-retention">' . esc_html__( 'Activity log retention (days, 0 = forever)', 'platform-helm' ) . '</label><input id="ph-retention" class="field-input" type="number" min="0" max="3650" name="' . esc_attr( $opt ) . '[activity_retention_days]" value="' . esc_attr( (string) $days ) . '"></div>';
		Ui::card_close();
		echo '</div>';
	}

	private function pref_toggle( string $opt, string $key, string $label, string $desc, bool $on ): void {
		echo '<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 0;border-bottom:1px solid var(--border)">';
		echo '<div><p style="font-size:12px;font-weight:600;color:var(--text-primary)">' . esc_html( $label ) . '</p><p style="font-size:11px;color:var(--text-faint);margin-top:2px">' . esc_html( $desc ) . '</p></div>';
		echo '<label class="toggle"><input type="checkbox" name="' . esc_attr( $opt ) . '[' . esc_attr( $key ) . ']" value="1" ' . checked( $on, true, false ) . '><span class="toggle-slider"></span></label>';
		echo '</div>';
	}

	/**
	 * Tabler icon per module id (for the Modules list).
	 */
	private function module_icon( string $id ): string {
		$map = [
			'link_suggester'     => 'ti-wand',
			'link_architect'     => 'ti-topology-star-3',
			'link_health'        => 'ti-heart-rate-monitor',
			'link_assassin'      => 'ti-unlink',
			'persona_dashboards' => 'ti-layout-dashboard',
			'role_manager'       => 'ti-shield-lock',
			'activity_log'       => 'ti-timeline',
			'audit_trail'        => 'ti-history',
			'activity_intelligence' => 'ti-radar-2',
			'member_health'      => 'ti-heartbeat',
			'ai_assistant'       => 'ti-sparkles',
			'aeo_check'          => 'ti-robot',
			'meta_gen'           => 'ti-text-caption',
			'schema'             => 'ti-code',
			'gtm'                => 'ti-tag',
			'gsc_connector'      => 'ti-brand-google',
			'content_auditor'    => 'ti-clipboard-check',
			'ghost_purge'        => 'ti-ghost-2',
			'uploads_vault'      => 'ti-lock',
			'login_branding'     => 'ti-login',
		];
		/** Filter the module-id → Tabler icon map (lets add-ons register icons). */
		$map = (array) apply_filters( 'platform_helm_module_icons', $map );
		return $map[ $id ] ?? 'ti-puzzle';
	}

	/**
	 * URL of a module's own admin page, if it has one — so the page stays
	 * reachable now that most module pages are removed from the sidebar.
	 * Uses menu_page_url(), which resolves the correct parent (admin.php /
	 * tools.php / users.php) and still works after remove_submenu_page().
	 */
	private function module_page_url( string $id ): string {
		$pages = [
			'link_suggester'  => 'platform-helm-link-suggester',
			'link_architect'  => 'platform-helm-link-architect',
			'link_health'     => 'platform-helm-link-health',
			'link_assassin'   => 'platform-helm-link-assassin',
			'ai_assistant'    => 'platform-helm-ai',
			'gsc_connector'   => 'platform-helm-gsc',
			'content_auditor' => 'platform-helm-content-auditor',
			'ghost_purge'     => 'platform-helm-ghost-purge',
			'login_branding'  => 'platform-helm-login-branding',
			'gtm'             => 'platform-helm-gtm',
			'role_manager'    => 'platform-helm-roles',
			'activity_log'    => 'platform-helm-activity-log',
			'activity_intelligence' => 'platform-helm-staff-report',
			'member_health'   => 'platform-helm-at-risk-users',
		];
		/** Filter the module-id → page-slug map (lets add-ons register pages). */
		$pages = (array) apply_filters( 'platform_helm_module_pages', $pages );
		if ( ! isset( $pages[ $id ] ) ) {
			return '';
		}
		$url = menu_page_url( $pages[ $id ], false );
		return is_string( $url ) ? $url : '';
	}
}
