<?php
/**
 * Admin app page shell.
 *
 * @package Carticy\Conversions\Admin
 */

declare(strict_types=1);

namespace Carticy\Conversions\Admin;

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

/**
 * Mounts the React admin app with the carticy/admin-ui full-page takeover.
 *
 * The PHP shell owns only chrome: the menu page, the `cv-takeover` body class,
 * third-party notice suppression on our screen, asset enqueueing, and a small
 * boot object (URLs/version only). Every product fact - health, premium plan,
 * onboarding position - is fetched from the REST contracts so the first paint
 * can never disagree with the API (frontend renders state, never computes it).
 */
final class AdminPage {

	/**
	 * Menu/page slug (doubles as the takeover gate).
	 */
	public const PAGE_SLUG = 'carticy-conversions';

	/**
	 * Mount element id the bundle looks for.
	 */
	public const MOUNT_ID = 'carticy-conversions-admin-root';

	/**
	 * Register the admin hooks.
	 */
	public function register_hooks(): void {
		add_action( 'admin_menu', array( $this, 'register_menu' ) );
		add_filter( 'admin_body_class', array( $this, 'add_takeover_body_class' ) );
		add_action( 'in_admin_header', array( $this, 'remove_foreign_notices' ), 99 );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
	}

	/**
	 * Register the top-level admin page.
	 */
	public function register_menu(): void {
		if ( ! function_exists( 'add_menu_page' ) ) {
			return;
		}

		add_menu_page(
			__( 'Carticy Conversions', 'carticy-conversions-for-woocommerce' ),
			__( 'Conversions', 'carticy-conversions-for-woocommerce' ),
			'manage_woocommerce',
			self::PAGE_SLUG,
			array( $this, 'render_app' ),
			'dashicons-chart-line',
			56
		);
	}

	/**
	 * Render the single React mount point.
	 *
	 * The wrapper classes come from the bundle (`adminUiRoot()` adds `cv-root`);
	 * everything visible is rendered by the app from REST state.
	 */
	public function render_app(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		echo '<div id="' . esc_attr( self::MOUNT_ID ) . '"></div>';
	}

	/**
	 * Add the design-system takeover body class on our screen only.
	 *
	 * @param string $classes Space-separated body classes.
	 * @return string
	 */
	public function add_takeover_body_class( $classes ): string {
		$classes = (string) $classes;

		return $this->is_plugin_screen() ? $classes . ' cv-takeover' : $classes;
	}

	/**
	 * Remove third-party admin notices on our screen; the app surfaces its own
	 * messages with cv-banner components.
	 */
	public function remove_foreign_notices(): void {
		if ( ! $this->is_plugin_screen() ) {
			return;
		}

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

	/**
	 * Enqueue the compiled app bundle + design-system CSS on our screen only.
	 *
	 * @param mixed $hook_suffix Current admin page hook suffix.
	 */
	public function enqueue_assets( $hook_suffix = '' ): void {
		if ( 'toplevel_page_' . self::PAGE_SLUG !== (string) $hook_suffix ) {
			return;
		}

		$base    = $this->plugin_url();
		$version = defined( 'CARTICY_CONVERSIONS_VERSION' ) ? CARTICY_CONVERSIONS_VERSION : '1.0.0';

		// Compiled design-system + app CSS (tokens/components bundled via
		// postcss-import; vendor/carticy never ships). Chrome is a separate
		// handle by doctrine: it styles host chrome outside .cv-root, gated
		// entirely by the body class.
		wp_enqueue_style( 'carticy-conversions-admin', $base . 'assets/css/dist/admin.css', array(), $version );
		wp_enqueue_style( 'carticy-conversions-admin-chrome', $base . 'assets/css/dist/admin-chrome.css', array( 'carticy-conversions-admin' ), $version );

		// wp-api-fetch carries the REST nonce + root middleware automatically.
		wp_enqueue_script(
			'carticy-conversions-admin',
			$base . 'assets/js/dist/admin.js',
			array( 'wp-element', 'wp-api-fetch', 'wp-i18n' ),
			$version,
			true
		);

		if ( function_exists( 'wp_set_script_translations' ) ) {
			wp_set_script_translations( 'carticy-conversions-admin', 'carticy-conversions-for-woocommerce' );
		}

		wp_add_inline_script(
			'carticy-conversions-admin',
			'window.carticyConversionsAdmin = ' . wp_json_encode( $this->boot_data( $base, (string) $version ) ) . ';',
			'before'
		);
	}

	/**
	 * Build the boot object: URLs and version only - no product state.
	 *
	 * @param string $base Plugin base URL.
	 * @param string $version Plugin version.
	 * @return array<string, string>
	 */
	private function boot_data( string $base, string $version ): array {
		return array(
			'restNamespace' => defined( 'CARTICY_CONVERSIONS_REST_NAMESPACE' ) ? CARTICY_CONVERSIONS_REST_NAMESPACE : 'carticy-conversions/v1',
			'mountId'       => self::MOUNT_ID,
			'version'       => $version,
			'pluginUrl'     => $base,
			'assetsBase'    => $base . 'assets/images/guide/',
			'shopUrl'       => function_exists( 'home_url' ) ? (string) home_url( '/' ) : '',
			'adminUrl'      => function_exists( 'admin_url' ) ? (string) admin_url() : '',
		);
	}

	/**
	 * Resolve the plugin base URL.
	 *
	 * @return string
	 */
	private function plugin_url(): string {
		if ( defined( 'CARTICY_CONVERSIONS_URL' ) ) {
			return (string) CARTICY_CONVERSIONS_URL;
		}

		return function_exists( 'plugin_dir_url' ) ? (string) plugin_dir_url( dirname( __DIR__ ) . '/carticy-conversions-for-woocommerce.php' ) : '';
	}

	/**
	 * Whether the current request renders our admin screen.
	 *
	 * @return bool
	 */
	private function is_plugin_screen(): bool {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page detection for asset/notice gating.
		$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['page'] ) ) : '';

		return self::PAGE_SLUG === $page;
	}
}
