<?php
/**
 * Admin menu and screen registration.
 *
 * @package RewindBrevoFormBridge
 */

namespace RewindBrevoFormBridge\Admin;

defined( 'ABSPATH' ) || exit;

/**
 * One top-level menu whose submenu items are hash routes into the same SPA.
 *
 * Every submenu entry points at the same page slug with a different hash, so
 * WordPress renders one screen and the router picks the view. The page
 * callback echoes exactly one mount node and nothing else.
 *
 * @since 0.4.0
 */
class AdminMenu {

	/**
	 * Menu and page slug.
	 *
	 * @var string
	 */
	const SLUG = 'rewind-form-bridge-for-brevo';

	/**
	 * Screen hook suffix, captured so the asset loader can gate on it.
	 *
	 * @var string
	 */
	private string $hook = '';

	/**
	 * Attach admin hooks.
	 *
	 * @since 0.4.0
	 * @return void
	 */
	public function register_hooks(): void {
		add_action( 'admin_menu', array( $this, 'register_menu' ) );
		add_action( 'admin_head', array( $this, 'hide_foreign_notices' ) );
	}

	/**
	 * The screen hook suffix this plugin owns.
	 *
	 * @since 0.4.0
	 * @return string Empty until admin_menu has run.
	 */
	public function hook(): string {
		return $this->hook;
	}

	/**
	 * The routes exposed as submenu entries.
	 *
	 * @since 0.4.0
	 * @return array<int, array{route:string,label:string}>
	 */
	private function routes(): array {
		return array(
			array(
				'route' => 'dashboard',
				'label' => __( 'Dashboard', 'rewind-form-bridge-for-brevo' ),
			),
			array(
				'route' => 'connections',
				'label' => __( 'Connections', 'rewind-form-bridge-for-brevo' ),
			),
			array(
				'route' => 'mappings',
				'label' => __( 'Form Mappings', 'rewind-form-bridge-for-brevo' ),
			),
			array(
				'route' => 'logs',
				'label' => __( 'Logs', 'rewind-form-bridge-for-brevo' ),
			),
			array(
				'route' => 'settings',
				'label' => __( 'Settings', 'rewind-form-bridge-for-brevo' ),
			),
			array(
				'route' => 'help',
				'label' => __( 'Help', 'rewind-form-bridge-for-brevo' ),
			),
		);
	}

	/**
	 * Register the top-level menu and its hash-routed submenu.
	 *
	 * @since 0.4.0
	 * @return void
	 */
	public function register_menu(): void {
		$hook = add_menu_page(
			__( 'Brevo Bridge', 'rewind-form-bridge-for-brevo' ),
			__( 'Brevo Bridge', 'rewind-form-bridge-for-brevo' ),
			'manage_options',
			self::SLUG,
			array( $this, 'render' ),
			'dashicons-email-alt2',
			81
		);

		if ( is_string( $hook ) ) {
			$this->hook = $hook;
		}

		foreach ( $this->routes() as $index => $entry ) {
			if ( 0 === $index ) {
				// The first entry re-uses the parent slug so WordPress does
				// not render a duplicate "Brevo Bridge" child.
				add_submenu_page(
					self::SLUG,
					$entry['label'],
					$entry['label'],
					'manage_options',
					self::SLUG,
					array( $this, 'render' )
				);

				continue;
			}

			/*
			 * The rest are deep links into the same screen. The slug is a
			 * complete URL rather than a page slug, and the callback is
			 * deliberately empty: registering a callback would make
			 * WordPress rebuild the href with add_query_arg(), which
			 * rawurlencodes the '#' into %23 and destroys the hash route.
			 * With no callback the slug is emitted verbatim.
			 */
			add_submenu_page(
				self::SLUG,
				$entry['label'],
				$entry['label'],
				'manage_options',
				'admin.php?page=' . self::SLUG . '#/' . $entry['route'],
				''
			);
		}
	}

	/**
	 * Suppress unrelated admin notices on this plugin's screen only.
	 *
	 * The SPA owns its viewport; third-party notices break the layout and
	 * are re-surfaced in the app's own notice slot when they belong to us.
	 *
	 * @since 0.4.0
	 * @return void
	 */
	public function hide_foreign_notices(): void {
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;

		if ( null === $screen || '' === $this->hook || $screen->id !== $this->hook ) {
			return;
		}

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

	/**
	 * The mount node. Exactly one element, no logic.
	 *
	 * @since 0.4.0
	 * @return void
	 */
	public function render(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		/**
		 * Fires inside this plugin's admin screen, above the app mount node.
		 *
		 * Notices printed here survive the admin_notices purge above, which
		 * is what makes this the right place for messages the app itself
		 * needs to show before its bundle can run.
		 *
		 * @since 0.4.0
		 */
		do_action( 'rbfb_admin_before_app' );

		echo '<div id="rbfb-admin"></div>';
	}
}
