<?php
/**
 * Hide Update Notifications Module
 *
 * @package HideUpdateNotifications
 * @since 1.0.0
 */

namespace HideUpdateNotifications;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID = 'hide-update-notifications';
	private const MODULE_VERSION = '1.2.0';

	private ?array $settings_cache = null;

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

	public function getName(): string {
		return __( 'Hide Update Notifications', 'wp-powersuite' );
	}

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

	public function getDescription(): string {
		return __( 'Quieter update nags in the admin for teams that patch on their own schedule.', 'wp-powersuite' );
	}

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

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

		$settings    = $this->getSettings();
		$hide_plugin = ! empty( $settings['hide_plugin_updates'] );
		$hide_theme  = ! empty( $settings['hide_theme_updates'] );
		$hide_core   = ! empty( $settings['hide_core_updates'] );
		$hide_php    = ! empty( $settings['hide_php_update_notice'] );

		if ( $hide_plugin ) {
			add_filter( 'site_transient_update_plugins', [ $this, 'hidePluginUpdates' ], 999 );
			add_filter( 'transient_update_plugins', [ $this, 'hidePluginUpdates' ], 999 );
			add_action( 'admin_menu', [ $this, 'removePluginUpdateMenu' ], 999 );
		}

		if ( $hide_theme ) {
			add_filter( 'site_transient_update_themes', [ $this, 'hideThemeUpdates' ], 999 );
			add_filter( 'transient_update_themes', [ $this, 'hideThemeUpdates' ], 999 );
			add_action( 'admin_menu', [ $this, 'removeThemeUpdateMenu' ], 999 );
		}

		if ( $hide_core ) {
			add_filter( 'site_transient_update_core', [ $this, 'hideCoreUpdates' ], 999 );
			add_filter( 'transient_update_core', [ $this, 'hideCoreUpdates' ], 999 );
			add_action( 'admin_menu', [ $this, 'removeCoreUpdateMenu' ], 999 );
			add_action( 'admin_init', [ $this, 'removeUpdateNag' ], 999 );
			add_action( 'admin_init', [ $this, 'removeMaintenanceNag' ], 999 );
		}

		if ( $hide_plugin || $hide_theme || $hide_core ) {
			add_filter( 'wp_get_update_data', [ $this, 'filterUpdateData' ], 999 );
			add_action( 'admin_head', [ $this, 'outputHideStyles' ], 999 );
		}

		if ( $hide_php ) {
			add_action( 'wp_dashboard_setup', [ $this, 'removePhpDashboardWidget' ], PHP_INT_MAX );
			add_filter( 'site_status_tests', [ $this, 'removePhpVersionTest' ], 999 );

			if ( ! $hide_plugin && ! $hide_theme && ! $hide_core ) {
				add_action( 'admin_head', [ $this, 'outputHideStyles' ], 999 );
			}
		}
	}

	public function hidePluginUpdates( $value ) {
		if ( ! is_object( $value ) || ! isset( $value->response ) ) {
			return $value;
		}

		$value->response = [];
		return $value;
	}

	public function hideThemeUpdates( $value ) {
		if ( ! is_object( $value ) || ! isset( $value->response ) ) {
			return $value;
		}

		$value->response = [];
		return $value;
	}

	public function hideCoreUpdates( $value ) {
		if ( ! is_object( $value ) || ! isset( $value->updates ) ) {
			return $value;
		}

		$value->updates = [];
		return $value;
	}

	public function removePluginUpdateMenu(): void {
		global $submenu;

		if ( ! isset( $submenu['plugins.php'] ) ) {
			return;
		}

		foreach ( $submenu['plugins.php'] as $key => $item ) {
			if ( isset( $item[2] ) && $item[2] === 'plugins.php' && isset( $item[0] ) ) {
				$submenu['plugins.php'][ $key ][0] = preg_replace(
					'/<span[^>]*class=["\'][^"\']*update-plugins[^"\']*["\'][^>]*>.*?<\/span>/i',
					'',
					$submenu['plugins.php'][ $key ][0]
				);
			}
		}
	}

	public function removeThemeUpdateMenu(): void {
		global $submenu;

		if ( ! isset( $submenu['themes.php'] ) ) {
			return;
		}

		foreach ( $submenu['themes.php'] as $key => $item ) {
			if ( isset( $item[2] ) && $item[2] === 'themes.php' && isset( $item[0] ) ) {
				$submenu['themes.php'][ $key ][0] = preg_replace(
					'/<span[^>]*class=["\'][^"\']*update-plugins[^"\']*["\'][^>]*>.*?<\/span>/i',
					'',
					$submenu['themes.php'][ $key ][0]
				);
			}
		}
	}

	public function removeCoreUpdateMenu(): void {
		global $menu, $submenu;

		foreach ( $menu as $key => $item ) {
			if ( isset( $item[2], $item[0] ) && $item[2] === 'index.php' ) {
				$menu[ $key ][0] = preg_replace(
					'/<span[^>]*class=["\'][^"\']*update-plugins[^"\']*["\'][^>]*>.*?<\/span>/i',
					'',
					$menu[ $key ][0]
				);
			}
		}

		if ( ! isset( $submenu['index.php'] ) ) {
			return;
		}

		foreach ( $submenu['index.php'] as $key => $item ) {
			if ( isset( $item[2], $item[0] ) && $item[2] === 'update-core.php' ) {
				$submenu['index.php'][ $key ][0] = preg_replace(
					'/<span[^>]*class=["\'][^"\']*update-plugins[^"\']*["\'][^>]*>.*?<\/span>/i',
					'',
					$submenu['index.php'][ $key ][0]
				);
			}
		}
	}

	/**
	 * Remove core update nag banner.
	 */
	public function removeUpdateNag(): void {
		remove_action( 'admin_notices', 'update_nag', 3 );
		remove_action( 'network_admin_notices', 'update_nag', 3 );
	}

	/**
	 * Remove maintenance mode nag (core updates only).
	 */
	public function removeMaintenanceNag(): void {
		remove_action( 'admin_notices', 'maintenance_nag', 10 );
		remove_action( 'network_admin_notices', 'maintenance_nag', 10 );
	}

	public function removePhpDashboardWidget(): void {
		foreach ( [ 'normal', 'side', 'column3', 'column4' ] as $context ) {
			remove_meta_box( 'dashboard_php_nag', 'dashboard', $context );
		}
	}

	/**
	 * @param array{counts?: array<string, int>, title?: string} $update_data Update summary from core.
	 * @return array{counts: array<string, int>, title: string}
	 */
	public function filterUpdateData( array $update_data ): array {
		$settings = $this->getSettings();
		$counts   = isset( $update_data['counts'] ) && is_array( $update_data['counts'] ) ? $update_data['counts'] : [];

		if ( ! empty( $settings['hide_core_updates'] ) ) {
			$counts['wordpress'] = 0;
		}
		if ( ! empty( $settings['hide_plugin_updates'] ) ) {
			$counts['plugins'] = 0;
		}
		if ( ! empty( $settings['hide_theme_updates'] ) ) {
			$counts['themes'] = 0;
		}

		$counts['total'] = (int) ( $counts['plugins'] ?? 0 ) +
			(int) ( $counts['themes'] ?? 0 ) +
			(int) ( $counts['wordpress'] ?? 0 ) +
			(int) ( $counts['translations'] ?? 0 );

		$update_data['counts'] = $counts;
		$update_data['title']  = $update_data['title'] ?? '';

		return $update_data;
	}

	public function outputHideStyles(): void {
		$settings = $this->getSettings();
		$rules    = [];

		if ( ! empty( $settings['hide_plugin_updates'] ) ) {
			$rules[] = '#menu-plugins .update-plugins';
			$rules[] = '.plugins .update-count';
			$rules[] = '.plugins .plugin-update-tr';
			$rules[] = '.plugins-php .update-message';
		}

		if ( ! empty( $settings['hide_theme_updates'] ) ) {
			$rules[] = '#menu-appearance .update-plugins';
			$rules[] = '.themes .update-count';
			$rules[] = '.themes .theme-update-tr';
			$rules[] = '.themes-php .update-message';
		}

		if ( ! empty( $settings['hide_core_updates'] ) ) {
			$rules[] = '#menu-dashboard .update-plugins';
			$rules[] = '.update-nag';
		}

		if ( ! empty( $settings['hide_php_update_notice'] ) ) {
			$rules[] = '#dashboard_php_nag';
			$rules[] = '.update-php';
		}

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

		$selector = implode( ",\n\t\t\t", $rules );
		?>
		<style id="wp-powersuite-hide-update-notifications">
			<?php echo esc_html( $selector ); ?> {
				display: none !important;
			}
		</style>
		<?php
	}

	public function removePhpVersionTest( array $tests ): array {
		if ( isset( $tests['direct']['php_version'] ) ) {
			unset( $tests['direct']['php_version'] );
		}
		if ( isset( $tests['async']['php_version'] ) ) {
			unset( $tests['async']['php_version'] );
		}
		return $tests;
	}

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

		$settings = $this->moduleSettings()->all( [] );
		$defaults = [
			'hide_plugin_updates'    => false,
			'hide_theme_updates'     => false,
			'hide_core_updates'      => false,
			'hide_php_update_notice' => false,
		];

		$this->settings_cache = is_array( $settings ) ? array_merge( $defaults, $settings ) : $defaults;
		return $this->settings_cache;
	}
}
