<?php
/**
 * Admin assets handler.
 *
 * @package OpusPriceBuilder\Admin
 */

declare(strict_types=1);

namespace OpusPriceBuilder\Admin;

use OpusPriceBuilder\Locations;

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

/**
 * Handles enqueueing of admin scripts and styles.
 */
class AdminAssets {

	/**
	 * Constructor.
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueueAssets' ) );
	}

	/**
	 * Current admin hook.
	 *
	 * @var string
	 */
	private string $currentHook = '';

	/**
	 * Enqueue admin scripts and styles.
	 *
	 * @param string $hook The current admin page hook.
	 * @return void
	 */
	public function enqueueAssets( string $hook ): void {
		// Only load on our plugin pages.
		if ( ! $this->isPluginPage( $hook ) ) {
			return;
		}

		$this->currentHook = $hook;
		$this->enqueueStyles();
		$this->enqueueScripts( $hook );
	}

	/**
	 * Check if current page is our plugin page.
	 *
	 * @param string $hook The current admin page hook.
	 * @return bool
	 */
	private function isPluginPage( string $hook ): bool {
		$plugin_pages = array(
			'toplevel_page_opus-price-builder',
			'price-builder_page_price-builder-templates',
			'price-builder_page_price-builder-settings',
		);

		return in_array( $hook, $plugin_pages, true );
	}

	/**
	 * Check if this is the settings page.
	 *
	 * @param string $hook The current admin page hook.
	 * @return bool
	 */
	private function isSettingsPage( string $hook ): bool {
		return 'price-builder_page_price-builder-settings' === $hook;
	}

	/**
	 * Enqueue styles.
	 *
	 * @return void
	 */
	private function enqueueStyles(): void {
		$css_file = OPPB_PLUGIN_DIR . 'assets/dist/main.css';

		if ( file_exists( $css_file ) ) {
			wp_enqueue_style(
				'opus-price-builder-admin',
				OPPB_PLUGIN_URL . 'assets/dist/main.css',
				array(),
				$this->getAssetVersion( $css_file )
			);
		}
	}

	/**
	 * Enqueue scripts.
	 *
	 * @param string $hook The current admin page hook.
	 * @return void
	 */
	private function enqueueScripts( string $hook ): void {
		// Determine which JS file to load based on the page
		$is_settings = $this->isSettingsPage( $hook );
		$js_filename = $is_settings ? 'settings.js' : 'main.js';
		$js_file     = OPPB_PLUGIN_DIR . 'assets/dist/' . $js_filename;

		if ( file_exists( $js_file ) ) {
			// Enqueue WordPress media library BEFORE our script (for media picker)
			if ( ! $is_settings ) {
				wp_enqueue_media();
			}

			// Register wp-element dependency (which includes React and ReactDOM)
			wp_enqueue_script( 'wp-element' );

			// Add inline script to create React JSX runtime shim for Vite
			// WordPress exposes React through wp.element, we need to map it to globals
			wp_add_inline_script(
				'wp-element',
				'window.React = window.React || wp.element;
				window.ReactDOM = window.ReactDOM || wp.element;
				window.ReactJSXRuntime = window.ReactJSXRuntime || {
					jsx: wp.element.createElement,
					jsxs: wp.element.createElement,
					Fragment: wp.element.Fragment
				};',
				'after'
			);

			$dependencies = $is_settings
				? array( 'wp-element' )
				: array( 'wp-element', 'media-editor', 'media-views' );

			$script_handle = 'opus-price-builder-admin';

			wp_register_script(
				$script_handle,
				OPPB_PLUGIN_URL . 'assets/dist/' . $js_filename,
				$dependencies,
				$this->getAssetVersion( $js_file ),
				array(
					'in_footer' => true,
					'strategy'  => 'defer',
				)
			);

			// Add type="module" for ES modules support
			add_filter(
				'script_loader_tag',
				function ( $tag, $handle ) use ( $script_handle ) {
					if ( $handle === $script_handle ) {
						return str_replace( ' src=', ' type="module" src=', $tag );
					}
					return $tag;
				},
				10,
				2
			);

			wp_enqueue_script( $script_handle );

			wp_localize_script(
				$script_handle,
				'oppbAdmin',
				$this->getScriptData()
			);
		}
	}

	/**
	 * Get script localization data.
	 *
	 * @return array<string, mixed>
	 */
	private function getScriptData(): array {
		return array(
			'apiUrl'      => rest_url( 'opus-price-builder/v1' ),
			'nonce'       => wp_create_nonce( 'wp_rest' ),
			'adminUrl'    => admin_url(),
			'pluginUrl'   => OPPB_PLUGIN_URL,
			'assetsUrl'   => OPPB_PLUGIN_URL . 'assets/',
			'version'     => OPPB_VERSION,
			'currency'    => array(
				// Decode HTML entities (e.g., &#36; -> $) for proper display in React/Canvas.
				'symbol'             => html_entity_decode( get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8' ),
				'code'               => get_woocommerce_currency(),
				'position'           => get_option( 'woocommerce_currency_pos' ),
				'decimals'           => wc_get_price_decimals(),
				'decimal_separator'  => wc_get_price_decimal_separator(),
				'thousand_separator' => wc_get_price_thousand_separator(),
			),
			// Available locations from centralized Locations class.
			'locations'   => Locations::getForAdmin(),
			// Font families grouped by type.
			'fonts'       => $this->getFontsData(),
			'render_mode' => apply_filters( 'oppb_render_mode', 'ssr' ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
			// License/Pro status from Freemius.
			'license'     => $this->getLicenseData(),
			'i18n'        => array(
				'save'     => __( 'Save', 'opus-price-builder' ),
				'export'   => __( 'Export', 'opus-price-builder' ),
				'preview'  => __( 'Preview', 'opus-price-builder' ),
				'settings' => __( 'Settings', 'opus-price-builder' ),
				'delete'   => __( 'Delete', 'opus-price-builder' ),
				'cancel'   => __( 'Cancel', 'opus-price-builder' ),
			),
		);
	}

	/**
	 * Get license data for the frontend.
	 *
	 * @return array<string, mixed>
	 */
	private function getLicenseData(): array {
		$is_pro = false;
		$plan   = 'free';
		$url    = '';

		// Check Freemius license status
		if ( function_exists( '\OpusPriceBuilder\oppb_fs' ) ) {
			$fs     = \OpusPriceBuilder\oppb_fs();
			$is_pro = \OpusPriceBuilder\oppb_can_use_premium_code();
			$plan   = $fs->is_trial() ? 'trial' : ( $fs->is_paying() ? 'pro' : 'free' );
			$url    = $fs->get_upgrade_url();
		}

		return array(
			'isPro'      => $is_pro,
			'plan'       => $plan,
			'upgradeUrl' => $url,
		);
	}

	/**
	 * Get fonts data organized by groups.
	 *
	 * @return array<string, array<string, mixed>>
	 */
	private function getFontsData(): array {
		return array(
			'standard' => $this->getStandardFonts(),
			'google'   => $this->getGoogleFonts(),
			'custom'   => $this->getCustomFonts(),
		);
	}

	/**
	 * Get standard system fonts.
	 *
	 * @return array<int, array<string, string>>
	 */
	private function getStandardFonts(): array {
		return array(
			array(
				'value' => 'Arial, sans-serif',
				'label' => 'Arial',
			),
			array(
				'value' => 'Helvetica, sans-serif',
				'label' => 'Helvetica',
			),
			array(
				'value' => 'Georgia, serif',
				'label' => 'Georgia',
			),
			array(
				'value' => 'Times New Roman, serif',
				'label' => 'Times New Roman',
			),
			array(
				'value' => 'Courier New, monospace',
				'label' => 'Courier New',
			),
			array(
				'value' => 'Verdana, sans-serif',
				'label' => 'Verdana',
			),
			array(
				'value' => 'Trebuchet MS, sans-serif',
				'label' => 'Trebuchet MS',
			),
			array(
				'value' => 'Tahoma, sans-serif',
				'label' => 'Tahoma',
			),
			array(
				'value' => 'Impact, sans-serif',
				'label' => 'Impact',
			),
			array(
				'value' => 'system-ui, sans-serif',
				'label' => 'System UI',
			),
		);
	}

	/**
	 * Get Google fonts list.
	 *
	 * @return array<int, array<string, string>>
	 */
	private function getGoogleFonts(): array {
		$google_fonts = array(
			array(
				'value' => 'Roboto',
				'label' => 'Roboto',
			),
			array(
				'value' => 'Open Sans',
				'label' => 'Open Sans',
			),
			array(
				'value' => 'Lato',
				'label' => 'Lato',
			),
			array(
				'value' => 'Montserrat',
				'label' => 'Montserrat',
			),
			array(
				'value' => 'Poppins',
				'label' => 'Poppins',
			),
			array(
				'value' => 'Inter',
				'label' => 'Inter',
			),
			array(
				'value' => 'Oswald',
				'label' => 'Oswald',
			),
			array(
				'value' => 'Raleway',
				'label' => 'Raleway',
			),
			array(
				'value' => 'Nunito',
				'label' => 'Nunito',
			),
			array(
				'value' => 'Playfair Display',
				'label' => 'Playfair Display',
			),
			array(
				'value' => 'Merriweather',
				'label' => 'Merriweather',
			),
			array(
				'value' => 'Source Sans Pro',
				'label' => 'Source Sans Pro',
			),
			array(
				'value' => 'Ubuntu',
				'label' => 'Ubuntu',
			),
			array(
				'value' => 'Rubik',
				'label' => 'Rubik',
			),
			array(
				'value' => 'Work Sans',
				'label' => 'Work Sans',
			),
			array(
				'value' => 'Fira Sans',
				'label' => 'Fira Sans',
			),
			array(
				'value' => 'Barlow',
				'label' => 'Barlow',
			),
			array(
				'value' => 'DM Sans',
				'label' => 'DM Sans',
			),
			array(
				'value' => 'Quicksand',
				'label' => 'Quicksand',
			),
			array(
				'value' => 'Josefin Sans',
				'label' => 'Josefin Sans',
			),
			array(
				'value' => 'Bebas Neue',
				'label' => 'Bebas Neue',
			),
			array(
				'value' => 'Anton',
				'label' => 'Anton',
			),
			array(
				'value' => 'Fjalla One',
				'label' => 'Fjalla One',
			),
			array(
				'value' => 'Space Grotesk',
				'label' => 'Space Grotesk',
			),
			array(
				'value' => 'Outfit',
				'label' => 'Outfit',
			),
			array(
				'value' => 'Caveat',
				'label' => 'Caveat',
			),
			array(
				'value' => 'JetBrains Mono',
				'label' => 'JetBrains Mono',
			),
			array(
				'value' => 'Archivo Black',
				'label' => 'Archivo Black',
			),
		);

		/**
		 * Filter to modify Google fonts list.
		 *
		 * @param array<int, array<string, string>> $google_fonts Array of Google fonts.
		 */
		return apply_filters( 'oppb_google_fonts', $google_fonts );
	}

	/**
	 * Get custom fonts added via filter.
	 *
	 * @return array<int, array<string, string>>
	 */
	private function getCustomFonts(): array {
		/**
		 * Filter to add custom fonts.
		 *
		 * Example usage:
		 * add_filter( 'oppb_custom_fonts', function( $fonts ) {
		 *     $fonts[] = array(
		 *         'value' => 'My Custom Font, sans-serif',
		 *         'label' => 'My Custom Font',
		 *     );
		 *     return $fonts;
		 * } );
		 *
		 * @param array<int, array<string, string>> $fonts Array of custom fonts.
		 */
		return apply_filters( 'oppb_custom_fonts', array() );
	}

	/**
	 * Get asset version based on file modification time.
	 *
	 * @param string $file_path Absolute path to the file.
	 * @return string
	 */
	private function getAssetVersion( string $file_path ): string {
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG && file_exists( $file_path ) ) {
			return (string) filemtime( $file_path );
		}

		return OPPB_VERSION;
	}
}
