<?php
/**
 * Frontend asset enqueue handler.
 *
 * @package ThemeREX\AutoDealer
 * @version 1.0.0
 */

declare(strict_types=1);

namespace ThemeREX\AutoDealer\Frontend;

defined( 'ABSPATH' ) || exit;
use function ThemeREX\AutoDealer\getSettings;

/**
 * Registers and enqueues frontend CSS and JS on pages with plugin content.
 */
class Assets {

	/**
	 * Register hooks.
	 *
	 * @return void
	 */
	public function register(): void {
		add_action( 'wp_enqueue_scripts', array( $this, 'registerAssets' ), 5 );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueueAssets' ), 10 );
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueueBlockEditorAssets' ) );
	}

	/**
	 * Register all frontend assets (but do not enqueue yet).
	 *
	 * @return void
	 */
	public function registerAssets(): void {
		$version = defined( 'TRX_AD_VERSION' ) ? TRX_AD_VERSION : '1.0.0';
		$url     = TRX_AD_URL . 'assets/';

		wp_register_style(
			'trx-ad-frontend',
			$url . 'css/frontend.css',
			array(),
			$version
		);

		// Inline CSS variable overrides from Appearance settings. Attached
		// to the same handle so it loads anywhere `trx-ad-frontend` does
		// (archive, single, blocks, Elementor widgets, editor preview).
		// Every value is sanitized where the CSS is BUILT (each color runs
		// through sanitize_hex_color(), the radius is int-clamped 0-32 —
		// see buildAppearanceInlineCss()); wp_strip_all_tags() here is a
		// final output-side guard so nothing tag-shaped can ever reach the
		// printed <style> block.
		$inline = self::buildAppearanceInlineCss();
		if ( '' !== $inline ) {
			wp_add_inline_style( 'trx-ad-frontend', wp_strip_all_tags( $inline ) );
		}

		wp_register_script(
			'trx-ad-frontend',
			$url . 'js/frontend.js',
			array(),
			$version,
			array(
				'strategy'  => 'defer',
				'in_footer' => true,
			)
		);

		wp_register_script(
			'trx-ad-archive-filters',
			$url . 'js/archive-filters.js',
			array(),
			$version,
			array(
				'strategy'  => 'defer',
				'in_footer' => true,
			)
		);

		// Swiper (local vendor). Own handle ('trx-ad-swiper') so we never collide
		// with Elementor's 'swiper' handle, which points at a stripped v8 build
		// missing the swiper-icons @font-face (would break the gallery arrows).
		wp_register_style( 'trx-ad-swiper', $url . 'vendor/swiper/swiper-bundle.min.css', array(), '11.0' );
		wp_register_script( 'trx-ad-swiper', $url . 'vendor/swiper/swiper-bundle.min.js', array(), '11.0', true );

		// Media slider widget assets.
		wp_register_style( 'trx-ad-widget-media-slider', $url . 'css/widgets/media-slider.css', array( 'trx-ad-swiper' ), $version );
		wp_register_script( 'trx-ad-widget-media-slider', $url . 'js/widgets/media-slider.js', array( 'trx-ad-swiper' ), $version, true );

		// Featured carousel (Elementor widget + block) — data-attribute-driven
		// Swiper init, replaces the per-instance inline <script> (wp.org 2026-07).
		wp_register_script( 'trx-ad-widget-featured-carousel', $url . 'js/widgets/featured-carousel.js', array( 'trx-ad-swiper' ), $version, true );

		// 360° view widget — drag-to-rotate init, same inline-script replacement.
		wp_register_script( 'trx-ad-widget-view-360', $url . 'js/widgets/view-360.js', array(), $version, true );

		// Specs highlights widget.
		wp_register_style( 'trx-ad-widget-specs-highlights', $url . 'css/widgets/specs-highlights.css', array(), $version );

		// Listing form widget.
		wp_register_style( 'trx-ad-widget-listing-form', $url . 'css/widgets/listing-form.css', array(), $version );
		wp_register_script( 'trx-ad-widget-listing-form', $url . 'js/widgets/listing-form.js', array(), $version, true );

		// Localize trxAdData here (not inside enqueueAssets) so the data
		// is attached as soon as the script is registered. Elementor
		// widgets that pull `trx-ad-frontend` via get_script_depends() get
		// the data even on non-plugin-pages where enqueueAssets bails out.
		wp_localize_script(
			'trx-ad-frontend',
			'trxAdData',
			array(
				'restUrl'          => esc_url_raw( rest_url( TRX_AD_REST_NAMESPACE . '/' ) ),
				'restNonce'        => wp_create_nonce( 'wp_rest' ),
				'currencySymbol'   => getSettings( 'currency_symbol', '$' ),
				'units'            => getSettings( 'distance_unit', 'km' ),
				'compareFields'    => self::compareFieldConfig(),

				/*
				 * Favorites storage backend for the frontend JS: 'local'
				 * (localStorage, per-device) by default. Pro flips this to
				 * 'rest' for logged-in users via the `trx_ad_favorites_backend`
				 * filter so favorites sync to user-meta across devices (#36).
				 */
				'favoritesBackend' => (string) apply_filters( 'trx_ad_favorites_backend', 'local' ),
				'i18n'             => array(
					// Toast messages (announce what just happened — past tense).
					'addedToCompare'       => esc_html__( 'Added to compare', 'trx-auto-dealer' ),
					'removedFromCompare'   => esc_html__( 'Removed from compare', 'trx-auto-dealer' ),
					'addedToFavorites'     => esc_html__( 'Added to favorites', 'trx-auto-dealer' ),
					'removedFromFavorites' => esc_html__( 'Removed from favorites', 'trx-auto-dealer' ),
					// Toggle-button accessible labels (describe the next action — present tense).
					'addToCompare'         => esc_html__( 'Add to compare', 'trx-auto-dealer' ),
					'removeFromCompare'    => esc_html__( 'Remove from compare', 'trx-auto-dealer' ),
					'addToFavorites'       => esc_html__( 'Add to favorites', 'trx-auto-dealer' ),
					'removeFromFavorites'  => esc_html__( 'Remove from favorites', 'trx-auto-dealer' ),
					'compare'              => esc_html__( 'Compare', 'trx-auto-dealer' ),
					'maxCompare'           => esc_html__( 'Maximum 4 vehicles can be compared', 'trx-auto-dealer' ),
					'remove'               => esc_html__( 'Remove', 'trx-auto-dealer' ),
					// Lightbox controls.
					'closeLightbox'        => esc_html__( 'Close', 'trx-auto-dealer' ),
					'prevImage'            => esc_html__( 'Previous image', 'trx-auto-dealer' ),
					'nextImage'            => esc_html__( 'Next image', 'trx-auto-dealer' ),
					'yes'                  => esc_html__( 'Yes', 'trx-auto-dealer' ),
					'no'                   => esc_html__( 'No', 'trx-auto-dealer' ),
					'na'                   => esc_html__( '—', 'trx-auto-dealer' ),
				),
			)
		);
	}

	/**
	 * Field config for the comparison-page spec table. Each entry tells
	 * the JS hydrator how to label the row + format the value cell. `format`
	 * matches the formatter switch in frontend.js; `unit` is appended after
	 * the value when present.
	 *
	 * @return array<string, array{label: string, format: string, unit?: string}>
	 */
	/**
	 * Build the inline CSS that overrides plugin custom properties from
	 * Appearance settings. Returns '' when no overrides are set.
	 */
	public static function buildAppearanceInlineCss(): string {
		// Read through AdminSettings::getSettings() so the pre-1.0.14
		// radius sentinel (0 = "stylesheet default") is normalized in one place.
		$settings = \ThemeREX\AutoDealer\Admin\AdminSettings::getSettings();

		$map = array(
			'color_primary'       => '--trx-ad-color-primary',
			'color_primary_hover' => '--trx-ad-color-primary-hover',
			'color_success'       => '--trx-ad-color-success',
			'color_warning'       => '--trx-ad-color-warning',
			'color_danger'        => '--trx-ad-color-danger',
		);

		$rules = array();
		foreach ( $map as $key => $cssVar ) {
			$value = isset( $settings[ $key ] ) ? trim( (string) $settings[ $key ] ) : '';
			if ( '' === $value ) {
				continue;
			}
			$sanitized = sanitize_hex_color( $value );
			if ( ! is_string( $sanitized ) || '' === $sanitized ) {
				continue;
			}
			$rules[] = $cssVar . ': ' . $sanitized . ';';
		}

		// 0 is a real value (square corners) since 1.0.14 — only skip emitting
		// when the value matches the stylesheet default of 8px.
		$radius = max( 0, min( 32, isset( $settings['radius'] ) ? (int) $settings['radius'] : 8 ) );
		if ( 8 !== $radius ) {
			$rules[] = '--trx-ad-radius: ' . $radius . 'px;';
			$rules[] = '--trx-ad-radius-sm: ' . max( 0, $radius - 4 ) . 'px;';
			// At 0 every derivative is 0 too — "square corners" must not leave
			// the -lg cards (dealer card, modals) with a +4px residue.
			$rules[] = '--trx-ad-radius-lg: ' . ( 0 === $radius ? 0 : $radius + 4 ) . 'px;';
		}

		// "Use theme fonts" (tester feedback #14): drop the plugin's system-font
		// stack so .trx-ad-archive/.trx-ad-single inherit the theme typography.
		if ( ! empty( $settings['use_theme_fonts'] ) ) {
			$rules[] = '--trx-ad-font-family: inherit;';
		}

		if ( empty( $rules ) ) {
			return '';
		}

		return ':root{' . implode( '', $rules ) . '}';
	}

	public static function compareFieldConfig(): array {
		$mileage_unit = (string) getSettings( 'distance_unit', 'km' );
		return array(
			'price'            => array(
				'label'  => __( 'Price', 'trx-auto-dealer' ),
				'format' => 'price',
			),
			'sale_price'       => array(
				'label'  => __( 'Sale Price', 'trx-auto-dealer' ),
				'format' => 'price',
			),
			'year'             => array(
				'label'  => __( 'Year', 'trx-auto-dealer' ),
				'format' => 'int',
			),
			'mileage'          => array(
				'label'  => __( 'Mileage', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => $mileage_unit,
			),
			'body_style'       => array(
				'label'  => __( 'Body Style', 'trx-auto-dealer' ),
				'format' => 'titlecase',
			),
			'fuel_type'        => array(
				'label'  => __( 'Fuel Type', 'trx-auto-dealer' ),
				'format' => 'titlecase',
			),
			'transmission'     => array(
				'label'  => __( 'Transmission', 'trx-auto-dealer' ),
				'format' => 'titlecase',
			),
			'drivetrain'       => array(
				'label'  => __( 'Drivetrain', 'trx-auto-dealer' ),
				'format' => 'upper',
			),
			'condition_type'   => array(
				'label'  => __( 'Condition', 'trx-auto-dealer' ),
				'format' => 'titlecase',
			),
			'doors'            => array(
				'label'  => __( 'Doors', 'trx-auto-dealer' ),
				'format' => 'int',
			),
			'seats'            => array(
				'label'  => __( 'Seats', 'trx-auto-dealer' ),
				'format' => 'int',
			),
			'color_ext'        => array(
				'label'  => __( 'Exterior Color', 'trx-auto-dealer' ),
				'format' => 'titlecase',
			),
			'color_int'        => array(
				'label'  => __( 'Interior Color', 'trx-auto-dealer' ),
				'format' => 'titlecase',
			),
			'engine'           => array(
				'label'  => __( 'Engine', 'trx-auto-dealer' ),
				'format' => 'string',
			),
			'horsepower'       => array(
				'label'  => __( 'Horsepower', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'HP',
			),
			'torque'           => array(
				'label'  => __( 'Torque', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'Nm',
			),
			'weight'           => array(
				'label'  => __( 'Weight', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'kg',
			),
			'mpg_city'         => array(
				'label'  => __( 'City Fuel Economy', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'mpg',
			),
			'mpg_highway'      => array(
				'label'  => __( 'Highway Fuel Economy', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'mpg',
			),
			'mpg_combined'     => array(
				'label'  => __( 'Combined Fuel Economy', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'mpg',
			),
			'co2_emissions'    => array(
				'label'  => __( 'CO₂ Emissions', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'g/km',
			),
			'battery_capacity' => array(
				'label'  => __( 'Battery Capacity', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => 'kWh',
			),
			'electric_range'   => array(
				'label'  => __( 'Electric Range', 'trx-auto-dealer' ),
				'format' => 'unit',
				'unit'   => $mileage_unit,
			),
			'charge_time'      => array(
				'label'  => __( 'Charge Time', 'trx-auto-dealer' ),
				'format' => 'string',
			),
			'accident_free'    => array(
				'label'  => __( 'Accident Free', 'trx-auto-dealer' ),
				'format' => 'bool',
			),
			'vin'              => array(
				'label'  => __( 'VIN', 'trx-auto-dealer' ),
				'format' => 'string',
			),
			'stock_number'     => array(
				'label'  => __( 'Stock Number', 'trx-auto-dealer' ),
				'format' => 'string',
			),
		);
	}

	/**
	 * Conditionally enqueue assets on pages that display plugin content.
	 *
	 * @return void
	 */
	public function enqueueAssets(): void {
		if ( ! self::isPluginPage() ) {
			return;
		}

		wp_enqueue_style( 'trx-ad-frontend' );
		wp_enqueue_script( 'trx-ad-frontend' );

		// Archive page filters: cascading make→model, live count, URL state.
		if ( is_post_type_archive( 'trx_ad_listing' ) ) {
			wp_enqueue_script( 'trx-ad-archive-filters' );
			wp_localize_script(
				'trx-ad-archive-filters',
				'trxAdArchive',
				array(
					'restUrl'   => esc_url_raw( rest_url( TRX_AD_REST_NAMESPACE . '/' ) ),
					'restNonce' => wp_create_nonce( 'wp_rest' ),
					'i18n'      => array(
						'anyModel'    => esc_html__( 'Any model', 'trx-auto-dealer' ),
						/* translators: %d: number of matching results */
						'showResults' => esc_html__( 'Show %d', 'trx-auto-dealer' ),
					),
				)
			);
		}

		// Single listing page assets.
		if ( is_singular( 'trx_ad_listing' ) ) {
			wp_enqueue_style( 'trx-ad-widget-media-slider' );
			wp_enqueue_script( 'trx-ad-widget-media-slider' );
			wp_enqueue_style( 'trx-ad-widget-specs-highlights' );
			wp_enqueue_style( 'trx-ad-widget-listing-form' );
			wp_enqueue_script( 'trx-ad-widget-listing-form' );
			wp_localize_script(
				'trx-ad-widget-listing-form',
				'trxAdFormData',
				array(
					'restUrl'   => esc_url_raw( rest_url( TRX_AD_REST_NAMESPACE . '/' ) ),
					'restNonce' => wp_create_nonce( 'wp_rest' ),
				)
			);
		}

		// trxAdData is localized at register time (see registerAssets) so
		// it's attached even when an Elementor widget pulls in the script
		// on a non-plugin page.
	}

	/**
	 * Enqueue editor-side block registration + the frontend stylesheet.
	 *
	 * The same `frontend.css` is loaded inside the editor canvas so the
	 * server-side-rendered preview matches the front-end output. The JS
	 * file uses the WP runtime globals (no build pipeline needed).
	 *
	 * @return void
	 */
	public function enqueueBlockEditorAssets(): void {
		$version = defined( 'TRX_AD_VERSION' ) ? TRX_AD_VERSION : '1.0.0';
		$url     = TRX_AD_URL . 'assets/';

		wp_enqueue_script(
			'trx-ad-blocks-editor',
			$url . 'js/blocks-editor.js',
			array( 'wp-blocks', 'wp-element', 'wp-i18n', 'wp-components', 'wp-block-editor', 'wp-server-side-render', 'wp-api-fetch', 'wp-url' ),
			$version,
			true
		);

		// Load the wp.i18n JED catalogs (languages/*.json) for the editor
		// script — without this the bundled block-editor translations never
		// apply, even when the .mo files are present.
		wp_set_script_translations(
			'trx-ad-blocks-editor',
			'trx-auto-dealer',
			TRX_AD_PATH . 'languages'
		);

		// Reuse the same stylesheet inside the editor so previews match.
		if ( ! wp_style_is( 'trx-ad-frontend', 'registered' ) ) {
			wp_register_style( 'trx-ad-frontend', $url . 'css/frontend.css', array(), $version );
		}
		wp_enqueue_style( 'trx-ad-frontend' );
	}

	/**
	 * Determine if the current page displays plugin content.
	 *
	 * @return bool True if the page should load plugin assets.
	 */
	public static function isPluginPage(): bool {
		if ( is_singular( 'trx_ad_listing' ) || is_singular( 'trx_ad_dealer' ) ) {
			return true;
		}

		if ( is_post_type_archive( 'trx_ad_listing' ) || is_post_type_archive( 'trx_ad_dealer' ) ) {
			return true;
		}

		$vehicle_taxonomies = array(
			'trx_ad_make',
			'trx_ad_model',
			'trx_ad_body_style',
			'trx_ad_fuel_type',
			'trx_ad_transmission',
			'trx_ad_drivetrain',
			'trx_ad_condition',
			'trx_ad_vehicle_type',
			'trx_ad_color',
			'trx_ad_feature',
		);

		foreach ( $vehicle_taxonomies as $taxonomy ) {
			if ( is_tax( $taxonomy ) ) {
				return true;
			}
		}

		// Singular page/post with one of our blocks in the content.
		if ( is_singular() && function_exists( 'has_block' ) ) {
			$block_names = array(
				'trx-auto-dealer/search-form',
				'trx-auto-dealer/vehicle-grid',
				'trx-auto-dealer/vehicle-card',
				'trx-auto-dealer/specs-table',
				'trx-auto-dealer/contact-form',
				'trx-auto-dealer/dealer-info',
			);
			foreach ( $block_names as $block_name ) {
				if ( has_block( $block_name, get_post() ) ) {
					return true;
				}
			}
		}

		// Singular page/post with one of our shortcodes. The compare page,
		// favorites page, dealer dashboard, dealer directory, and inquiry-
		// form pages are all regular pages that depend on frontend.css/js
		// being enqueued.
		if ( is_singular() ) {
			$post = get_post();
			if ( $post instanceof \WP_Post && is_string( $post->post_content ) && '' !== $post->post_content ) {
				$shortcodes = array(
					'trx_ad_compare',
					'trx_ad_favorites',
					'trx_ad_dealer_dashboard',
					'trx_ad_dealer_directory',
					'trx_ad_inquiry_form',
				);
				foreach ( $shortcodes as $sc ) {
					if ( has_shortcode( $post->post_content, $sc ) ) {
						return true;
					}
				}
			}
		}

		/**
		 * Filter whether to load plugin frontend assets on the current page.
		 *
		 * @param bool $is_plugin_page Whether the current page is a plugin page.
		 */
		return (bool) apply_filters( 'trx_ad_is_plugin_page', false );
	}
}
