<?php
/**
 * Admin menu registration.
 *
 * @package StoreSheet
 */

declare( strict_types=1 );

namespace StoreSheet\Settings;

defined( 'ABSPATH' ) || exit;

class Menu {

	public function init(): void {
		add_action( 'admin_menu', array( $this, 'register_menu' ) );
		add_action( 'admin_head', array( $this, 'print_menu_icon_style' ) );
		add_filter( 'admin_footer_text', array( $this, 'remove_footer_text' ) );
		add_filter( 'update_footer', array( $this, 'remove_footer_text' ), 11 );

		// Late, so notices registered by other plugins during admin_init are
		// already on the hook and can be removed.
		add_action( 'in_admin_header', array( $this, 'suppress_foreign_notices' ), 99 );
	}

	public function remove_footer_text( string $text = '' ): string {
		return $this->is_plugin_screen() ? '' : $text;
	}

	/**
	 * Whether the current screen belongs to this plugin.
	 */
	private function is_plugin_screen(): bool {
		$screen = get_current_screen();

		return $screen && str_contains( $screen->id, 'storesheet' );
	}

	/**
	 * Clear other plugins' admin notices from StoreSheet's own screens.
	 *
	 * The admin is a single-page React app with its own layout, and WordPress
	 * prints every registered notice into the top of it regardless of whose it
	 * is. A page that opens with somebody else's licence nag or update prompt
	 * looks broken, and in a support screenshot it is impossible to tell which
	 * plugin the message belongs to.
	 *
	 * Scoped three ways, because "hide the notices" is easy to get too broad:
	 *
	 *  - Only on this plugin's screens. Every other admin page is untouched.
	 *  - Only the notice hooks, not `admin_init` or anything with side effects.
	 *  - `user_admin_notices` and `network_admin_notices` go too; leaving them
	 *    means a notice reappears on multisite for no discernible reason.
	 *
	 * WordPress core's own `admin_notices` output — the ones core prints
	 * directly rather than through a callback — is unaffected, and so is
	 * anything StoreSheet itself renders inside its React tree.
	 *
	 * Filterable, because a site owner who genuinely wants third-party notices
	 * here should not have to fork the plugin to get them back.
	 */
	public function suppress_foreign_notices(): void {
		if ( ! $this->is_plugin_screen() ) {
			return;
		}

		/**
		 * Filter whether to hide other plugins' admin notices on StoreSheet
		 * screens.
		 *
		 * @since 1.1.1
		 *
		 * @param bool $suppress Default true.
		 */
		if ( ! apply_filters( 'storesheet_suppress_admin_notices', true ) ) {
			return;
		}

		remove_all_actions( 'admin_notices' );
		remove_all_actions( 'all_admin_notices' );
		remove_all_actions( 'user_admin_notices' );
		remove_all_actions( 'network_admin_notices' );
	}

	public function register_menu(): void {
		add_menu_page(
			__( 'StoreSheet', 'storesheet' ),
			__( 'StoreSheet', 'storesheet' ),
			'manage_woocommerce',
			'storesheet',
			array( $this, 'render_page' ),
			'none', // Rendered as an adaptive CSS mask in print_menu_icon_style().
			56
		);

		// Rename the auto-generated first submenu (which otherwise duplicates the
		// top-level "StoreSheet" label) to "Dashboard". Same slug = same page.
		add_submenu_page(
			'storesheet',
			__( 'Dashboard', 'storesheet' ),
			__( 'Dashboard', 'storesheet' ),
			'manage_woocommerce',
			'storesheet',
			array( $this, 'render_page' )
		);
	}

	/**
	 * Print the admin-menu icon as a CSS mask.
	 *
	 * WordPress recolours native (dashicon) menu icons per state — dim at rest,
	 * bright when active/hovered. A static PNG/SVG icon can't do that. We render
	 * the StoreSheet mark as a `mask-image` painted with `currentColor`, so it
	 * inherits WordPress's own per-state icon colour and behaves like a native
	 * icon across every admin colour scheme.
	 *
	 * @return void
	 */
	public function print_menu_icon_style(): void {
		$mask = "url('" . $this->menu_icon_mask() . "') no-repeat center / 20px auto";
		$sel  = '#adminmenu #toplevel_page_storesheet';

		$css = "
			{$sel} .wp-menu-image { background-image: none !important; }
			{$sel} .wp-menu-image::before {
				content: '';
				display: block;
				width: 100%;
				height: 34px;
				padding: 0;
				background-color: currentColor;
				color: #a7aaad;
				-webkit-mask: {$mask};
				mask: {$mask};
			}
			{$sel}.wp-has-current-submenu .wp-menu-image::before,
			{$sel}.current .wp-menu-image::before,
			{$sel}.opensub .wp-menu-image::before,
			{$sel}:hover .wp-menu-image::before,
			{$sel} > a:focus .wp-menu-image::before { color: #fff; }
		";

		printf( "<style id='storesheet-menu-icon'>%s</style>\n", $this->minify_css( $css ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Base64 data-URI of the monochrome StoreSheet silhouette used as a mask.
	 *
	 * Shape only — the fill colour is irrelevant (the mask uses alpha); the
	 * visible colour comes from `currentColor` in {@see print_menu_icon_style()}.
	 *
	 * @return string
	 */
	private function menu_icon_mask(): string {
		$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">'
			// Spreadsheet.
			. '<rect x="2.3" y="2.3" width="9.6" height="12" rx="2" stroke="#000" stroke-width="1.7"/>'
			. '<path d="M2.3 7h9.6M7.1 2.3v12" stroke="#000" stroke-width="1.4"/>'
			// Sync badge (RefreshCw), matching the app logo.
			. '<g stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">'
			. '<path d="M11.6 14.1a3.1 3.1 0 0 1 5.2-1.3"/><path d="M17.1 11.3v1.9h-1.9"/>'
			. '<path d="M17 15a3.1 3.1 0 0 1-5.2 1.3"/><path d="M11.5 17.3v-1.9h1.9"/></g>'
			. '</svg>';

		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Inline SVG data-URI.
		return 'data:image/svg+xml;base64,' . base64_encode( $svg );
	}

	/**
	 * Collapse whitespace in a small inline CSS blob.
	 *
	 * @param string $css Raw CSS.
	 * @return string
	 */
	private function minify_css( string $css ): string {
		return trim( (string) preg_replace( '/\s+/', ' ', $css ) );
	}

	public function render_page(): void {
		wc_get_template(
			'admin/admin-page.php',
			array(),
			'storesheet/',
			STORESHEET_DIR . 'templates/'
		);
	}
}
