<?php

namespace CelerSearch\Admin;

defined( 'ABSPATH' ) || exit;

use CelerSearch\Interfaces\IRegistrable;

class Assets implements IRegistrable {

	/**
	 * List of scripts
	 * @var array|array[]
	 */
	protected array $scripts = [];

	/**
	 * List of styles
	 * @var array|array[]
	 */
	protected array $styles = [];

	/**
	 * List of global styles (enqueued on all admin pages)
	 * @var array|array[]
	 */
	protected array $global_styles = [];

	public function __construct() {

		$this->scripts = [
			'celersearch-admin' => [
				'src'       => CELERSEARCH_PLUGIN_URL . 'assets/admin/scripts.js',
				'deps'      => [ 'wp-i18n' ],
				// version intentionally omitted — see asset_version() for the
				// mtime-in-debug / plugin-version-in-prod resolution.
				'in_footer' => true,
				'localize'  => [
					'object' => 'CelerSearchAdmin',
					'i18n'   => dirname( __FILE__ ) . '/Strings.php'
				]
			]
		];

		$this->styles = [
			'celersearch-admin' => [
				'src' => CELERSEARCH_PLUGIN_URL . 'assets/admin/styles.css'
			],
		];

		$this->global_styles = [];

	}


	/**
	 * Registers certain group of hooks (actions/filters)
	 * @return void
	 */
	public function register() : void {
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
		add_action( 'init', [ $this, 'reqister_scripts' ], 12 );
	}

	/**
	 * Enqueue scripts in admin
	 * @return void
	 */
	public function enqueue_scripts() {
		// Always enqueue global styles on all admin pages
		foreach ( $this->global_styles as $handle => $style ) {
			wp_enqueue_style( $handle );
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Just checking admin page context
		$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
		// Exact match — the plugin registers a single top-level menu (slug
		// "celersearch") and uses hash-fragment routing for subpages, so the
		// admin bundle should only load on that one screen. A substring match
		// would (mis)load it on any third-party page whose slug contains
		// "celersearch".
		if ( 'celersearch' !== $page ) {
			return;
		}
		foreach ( $this->scripts as $key => $v ) {
			wp_enqueue_script( $key );
		}
		foreach ( $this->styles as $key => $v ) {
			wp_enqueue_style( $key );
		}

	}

	public function reqister_scripts(): void {
		$this->_register_scripts( $this->scripts );
		$this->_register_styles( $this->styles );
		$this->_register_styles( $this->global_styles );
	}

	/**
	 * Register scripts
	 *
	 * @param array $scripts
	 *
	 * @return void
	 */
	private function _register_scripts( $scripts ) {
		foreach ( $scripts as $handle => $script ) {
			$deps      = isset( $script['deps'] ) ? $script['deps'] : false;
			$in_footer = isset( $script['in_footer'] ) ? $script['in_footer'] : false;
			$version   = $this->asset_version( $script['src'], $script['version'] ?? null );

			wp_register_script( $handle, $script['src'], $deps, $version, $in_footer );
			if ( isset( $script['localize'] ) ) {
				$strings = include $script['localize']['i18n'];
				wp_localize_script( $handle, $script['localize']['object'], [
					'i18n' => $strings,
					'nonce' => wp_create_nonce( 'celersearch' ),
					'ajaxUrl' => admin_url( 'admin-ajax.php' ),
					'adminUrl' => admin_url(),
					'pluginUrl' => CELERSEARCH_PLUGIN_URL,
					'review' => $this->build_review_payload(),
				] );
			}
		}
	}

	/**
	 * Register styles
	 *
	 * @param array $styles
	 *
	 * @return void
	 */
	/**
	 * Resolve the version string for an asset.
	 *
	 * In production we use the static plugin version (deterministic, bumps on
	 * release). In WP_DEBUG we map the URL back to a file path and use mtime so
	 * every rebuild forces browsers to refetch the bundle without manual cache
	 * busting.
	 *
	 * @param string      $src      Public URL of the asset.
	 * @param string|null $explicit Caller-supplied override; wins when set.
	 *
	 * @return string
	 */
	private function asset_version( string $src, ?string $explicit ): string {
		if ( ! empty( $explicit ) ) {
			return (string) $explicit;
		}
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			$relative = ltrim( str_replace( CELERSEARCH_PLUGIN_URL, '', $src ), '/' );
			$path     = CELERSEARCH_PLUGIN_PATH . $relative;
			if ( file_exists( $path ) ) {
				return (string) filemtime( $path );
			}
		}
		return CELERSEARCH_PLUGIN_VERSION;
	}

	public function _register_styles( $styles ) {
		foreach ( $styles as $handle => $style ) {
			$deps = isset( $style['deps'] ) ? $style['deps'] : false;

			$version = $this->asset_version( $style['src'], $style['version'] ?? null );

			wp_register_style( $handle, $style['src'], $deps, $version );
		}
	}

	/**
	 * Compute the gate for the "rate the plugin" card.
	 *
	 * Server-authoritative so the frontend doesn't need to know about the
	 * WP option names or reimplement the engagement heuristics.
	 *
	 * @return array
	 */
	private function build_review_payload(): array {
		$review_url = defined( 'CELERSEARCH_REVIEW_URL' )
			? CELERSEARCH_REVIEW_URL
			: 'https://wordpress.org/support/plugin/celersearch/reviews/#new-post';

		$dismissed    = (bool) get_option( 'celersearch_review_dismissed', false );
		$activated_at = (int) get_option( 'celersearch_activated_at', 0 );

		// Three-day usage gate. If the timestamp is missing (legacy install
		// pre-dating the option), treat today as the activation date so the
		// card appears three days from now — not immediately.
		if ( $activated_at === 0 ) {
			update_option( 'celersearch_activated_at', time(), false );
			$activated_at = time();
		}
		$aged_enough = ( time() - $activated_at ) >= ( 3 * DAY_IN_SECONDS );

		$has_engagement = $this->has_review_engagement();

		return [
			'reviewUrl' => $review_url,
			'canShow'   => ( ! $dismissed && $aged_enough && $has_engagement ),
		];
	}

	/**
	 * Engagement signal: at least one service AND one index. Direct SELECT to
	 * avoid instantiating repositories during asset registration.
	 *
	 * @return bool
	 */
	private function has_review_engagement(): bool {
		global $wpdb;
		$suppress = $wpdb->suppress_errors( true );
		$services = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}celersearch_services" );
		$indices  = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}celersearch_indices" );
		$wpdb->suppress_errors( $suppress );

		return $services > 0 && $indices > 0;
	}

}