<?php
/**
 * Disable Dashboard Widgets Module
 *
 * @package DisableDashboardWidgets
 * @since 1.0.0
 */

namespace DisableDashboardWidgets;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID = 'disable-dashboard-widgets';
	private const MODULE_VERSION = '1.3.1';
	private const DISCOVERED_TRANSIENT = 'wpps_ddw_discovered_widgets';

	private ?array $settings_cache = null;

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Disable Dashboard Widgets', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	public function getDescription(): string {
		return __( 'Declutter the dashboard home by turning off widgets nobody uses. Switched-off widgets stay out of Screen Options and do not load extra scripts in the background.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return 'admin';
	}

	/**
	 * Core WordPress dashboard widgets (setting key => meta box id).
	 *
	 * @return array<string, string>
	 */
	public static function getKnownWidgets(): array {
		return [
			'welcome'         => 'welcome',
			'activity'        => 'dashboard_activity',
			'right_now'       => 'dashboard_right_now',
			'quick_press'     => 'dashboard_quick_press',
			'site_health'     => 'dashboard_site_health',
			'primary'         => 'dashboard_primary',
			'secondary'       => 'dashboard_secondary',
			'php_nag'         => 'dashboard_php_nag',
			'browser_nag'     => 'dashboard_browser_nag',
			'recent_comments' => 'dashboard_recent_comments',
			'recent_drafts'   => 'dashboard_recent_drafts',
			'incoming_links'  => 'dashboard_incoming_links',
			'plugins'         => 'dashboard_plugins',
		];
	}

	/**
	 * Human-readable labels for known widgets.
	 *
	 * @return array<string, string>
	 */
	public static function getKnownWidgetLabels(): array {
		return [
			'welcome'         => __( 'Welcome to WordPress', 'wp-powersuite' ),
			'activity'        => __( 'Activity', 'wp-powersuite' ),
			'right_now'       => __( 'At a Glance', 'wp-powersuite' ),
			'quick_press'     => __( 'Quick Draft', 'wp-powersuite' ),
			'site_health'     => __( 'Site Health Status', 'wp-powersuite' ),
			'primary'         => __( 'WordPress Events and News', 'wp-powersuite' ),
			'secondary'       => __( 'Other WordPress News', 'wp-powersuite' ),
			'php_nag'         => __( 'PHP Update Required', 'wp-powersuite' ),
			'browser_nag'     => __( 'Browser Update Required', 'wp-powersuite' ),
			'recent_comments' => __( 'Recent Comments', 'wp-powersuite' ),
			'recent_drafts'   => __( 'Recent Drafts', 'wp-powersuite' ),
			'incoming_links'  => __( 'Incoming Links', 'wp-powersuite' ),
			'plugins'         => __( 'Plugins', 'wp-powersuite' ),
		];
	}

	/**
	 * @return array<string, mixed>
	 */
	public function getDefaultSettings(): array {
		$defaults = [
			'disable_all'     => false,
			'custom_widgets'  => [],
		];

		foreach ( array_keys( self::getKnownWidgets() ) as $key ) {
			$defaults[ $key ] = false;
		}

		return $defaults;
	}

	/**
	 * Discovered third-party widgets cached from the last dashboard load.
	 *
	 * @return array<int, array{id: string, title: string}>
	 */
	public static function getDiscoveredWidgets(): array {
		$discovered = get_transient( self::DISCOVERED_TRANSIENT );
		if ( ! is_array( $discovered ) ) {
			return [];
		}

		$known_ids = array_values( self::getKnownWidgets() );
		$known_ids = array_filter(
			$known_ids,
			static fn( string $id ): bool => $id !== 'welcome'
		);

		$extra = [];
		foreach ( $discovered as $widget ) {
			if ( ! is_array( $widget ) || empty( $widget['id'] ) ) {
				continue;
			}
			$id = (string) $widget['id'];
			if ( in_array( $id, $known_ids, true ) ) {
				continue;
			}
			$extra[] = [
				'id'    => $id,
				'title' => isset( $widget['title'] ) ? (string) $widget['title'] : $id,
			];
		}

		return $extra;
	}

	protected function registerHooks(): void {
		if ( ! is_admin() ) {
			return;
		}

		add_action( 'admin_init', [ $this, 'maybeRemoveWelcomePanel' ] );
		// Discover after plugins/themes register widgets (default priority 10), before we remove any.
		add_action( 'wp_dashboard_setup', [ $this, 'cacheDiscoveredWidgets' ], PHP_INT_MAX - 1 );
		add_action( 'wp_dashboard_setup', [ $this, 'removeDashboardWidgets' ], PHP_INT_MAX );
	}

	public function maybeRemoveWelcomePanel(): void {
		$settings = $this->getSettings();
		if ( ! empty( $settings['disable_all'] ) || ! empty( $settings['welcome'] ) ) {
			remove_action( 'welcome_panel', 'wp_welcome_panel' );
		}
	}

	public function cacheDiscoveredWidgets(): void {
		global $wp_meta_boxes;

		if ( ! isset( $wp_meta_boxes['dashboard'] ) || ! is_array( $wp_meta_boxes['dashboard'] ) ) {
			return;
		}

		$widgets = [];

		foreach ( $wp_meta_boxes['dashboard'] as $priorities ) {
			if ( ! is_array( $priorities ) ) {
				continue;
			}
			foreach ( $priorities as $boxes ) {
				if ( ! is_array( $boxes ) ) {
					continue;
				}
				foreach ( $boxes as $widget_id => $data ) {
					$widget_id = (string) $widget_id;
					if ( $widget_id === '' || isset( $widgets[ $widget_id ] ) ) {
						continue;
					}
					// Skip empty/false boxes WordPress leaves after remove_meta_box().
					if ( empty( $data ) || ! is_array( $data ) ) {
						continue;
					}
					$title = isset( $data['title'] ) ? wp_strip_all_tags( (string) $data['title'] ) : $widget_id;
					$title = trim( (string) preg_replace( '/ <span.*span>/im', '', $title ) );
					$widgets[ $widget_id ] = [
						'id'    => $widget_id,
						'title' => $title !== '' ? $title : $widget_id,
					];
				}
			}
		}

		if ( $widgets === [] ) {
			return;
		}

		// Merge with the previous cache so widgets from intermittent plugins stay listed.
		$previous = get_transient( self::DISCOVERED_TRANSIENT );
		if ( is_array( $previous ) ) {
			foreach ( $previous as $widget ) {
				if ( ! is_array( $widget ) || empty( $widget['id'] ) ) {
					continue;
				}
				$id = (string) $widget['id'];
				if ( $id === '' || isset( $widgets[ $id ] ) ) {
					continue;
				}
				$widgets[ $id ] = [
					'id'    => $id,
					'title' => isset( $widget['title'] ) ? (string) $widget['title'] : $id,
				];
			}
		}

		set_transient( self::DISCOVERED_TRANSIENT, array_values( $widgets ), DAY_IN_SECONDS );
	}

	public function removeDashboardWidgets(): void {
		$settings = $this->getSettings();

		if ( ! empty( $settings['disable_all'] ) ) {
			$this->removeAllExceptPowerSuiteWidgets();
			return;
		}

		foreach ( self::getKnownWidgets() as $setting_key => $widget_id ) {
			if ( $widget_id === 'welcome' ) {
				continue;
			}
			if ( ! empty( $settings[ $setting_key ] ) ) {
				$this->removeWidgetFromDashboard( $widget_id );
			}
		}

		$custom = $settings['custom_widgets'] ?? [];
		if ( is_array( $custom ) ) {
			foreach ( $custom as $widget_id ) {
				if ( is_string( $widget_id ) && $widget_id !== '' ) {
					$this->removeWidgetFromDashboard( $widget_id );
				}
			}
		}
	}

	private function removeAllExceptPowerSuiteWidgets(): void {
		global $wp_meta_boxes;

		if ( ! isset( $wp_meta_boxes['dashboard'] ) || ! is_array( $wp_meta_boxes['dashboard'] ) ) {
			return;
		}

		$preserved = [];

		foreach ( $wp_meta_boxes['dashboard'] as $context => $priorities ) {
			if ( ! is_array( $priorities ) ) {
				continue;
			}
			foreach ( $priorities as $priority => $boxes ) {
				if ( ! is_array( $boxes ) ) {
					continue;
				}
				foreach ( $boxes as $box_id => $box_data ) {
					if ( ! str_starts_with( (string) $box_id, 'wpps_' ) ) {
						continue;
					}
					if ( ! isset( $preserved[ $context ] ) ) {
						$preserved[ $context ] = [];
					}
					if ( ! isset( $preserved[ $context ][ $priority ] ) ) {
						$preserved[ $context ][ $priority ] = [];
					}
					$preserved[ $context ][ $priority ][ $box_id ] = $box_data;
				}
			}
		}

		$wp_meta_boxes['dashboard'] = $preserved;
	}

	private function removeWidgetFromDashboard( string $widget_id ): void {
		foreach ( [ 'normal', 'side', 'column3', 'column4' ] as $context ) {
			remove_meta_box( $widget_id, 'dashboard', $context );
		}
	}

	private function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}

		$settings = $this->moduleSettings()->all( [] );
		if ( ! is_array( $settings ) ) {
			$settings = [];
		}

		$merged = array_merge( $this->getDefaultSettings(), $settings );

		if ( isset( $merged['custom_widgets'] ) && ! is_array( $merged['custom_widgets'] ) ) {
			$merged['custom_widgets'] = [];
		}

		$this->settings_cache = $merged;
		return $this->settings_cache;
	}
}
