<?php
/**
 * Frontend bootstrap.
 *
 * @package PRECO
 */

namespace PRECO\Includes\Frontend\Core;

use PRECO\Includes\Admin\Rest\GlobalStylesRest;
use PRECO\Includes\Common\AssetLoader;
use PRECO\Includes\Frontend\Pages\CartPageRecommendations;
use PRECO\Includes\Frontend\Pages\CheckoutPageRecommendations;
use PRECO\Includes\Frontend\Pages\OrderPageRecommendations;
use PRECO\Includes\Frontend\Pages\ProductPageRecommendations;
use PRECO\Includes\Frontend\Pages\ShopArchiveRecommendations;
use PRECO\Includes\Frontend\Pages\ShopPageRecommendations;
use PRECO\Includes\Frontend\Pages\PopupUpsellRecommendations;
use PRECO\Includes\Frontend\Pages\OrderBumpRecommendations;
use PRECO\Includes\Frontend\Core\RecentlyViewedTracker;
use PRECO\Includes\Preco;

defined( 'ABSPATH' ) || exit;

/**
 * Loads all frontend recommenders.
 */
class Frontend {

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

	/**
	 * Bootstrap frontend hooks once WooCommerce is confirmed active.
	 *
	 * @return void
	 */
	public function init() {
		if ( ! class_exists( 'WooCommerce' ) ) {
			return;
		}

		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ), 20 );

		// Label any cart line the builder's live preview added, so a missed
		// cleanup never confuses the admin looking at their own real cart.
		add_filter( 'woocommerce_cart_item_name', array( 'PRECO\Includes\Frontend\Core\PreviewMode', 'maybe_label_cart_item' ), 10, 2 );

		// The builder's live iframe should look like what a shopper sees —
		// hide the wp-admin toolbar the logged-in admin would otherwise see.
		if ( PreviewMode::is_active_request() ) {
			add_filter( 'show_admin_bar', '__return_false' );
		}

		new RecentlyViewedTracker();
		new ProductPageRecommendations();
		new ShopPageRecommendations();
		new ShopArchiveRecommendations();

		// Pro locations — never rendered on the real storefront without an
		// active license, but their hooks must still register during a
		// builder preview request. Otherwise the free-plan admin's live
		// iframe never reaches the PreviewMode::is_active_request() check
		// inside render_location() and Thank You/Cart/Checkout stay blank.
		if ( Preco::is_lc_active() || PreviewMode::is_active_request() ) {
			new OrderPageRecommendations();
			new CartPageRecommendations();
			new CheckoutPageRecommendations();
		}
		if ( Preco::is_lc_active() ) {
			new PopupUpsellRecommendations();
			new OrderBumpRecommendations();
		}
	}

	/**
	 * Enqueue frontend assets.
	 *
	 * Provides a stable place for user-written CSS overrides.
	 *
	 * @return void
	 */
	public function enqueue_assets() {
		$handle = 'preco-frontend';
		AssetLoader::enqueue_style( $handle, 'preco-frontend' );

		$handle2 = 'preco-common';
		AssetLoader::enqueue_style( $handle2, 'preco-common' );

		// Global widget style colors as CSS variables (PHP counterpart of
		// generateGlobalCss() in src/builder/utils/cssgenerator.js).
		$global_css = $this->generate_global_css();
		if ( $global_css ) {
			AssetLoader::add_inline_style( $handle2, $global_css );
		}

		// Set guest tracking cookie on page load for non-logged-in users.
		if ( ! is_user_logged_in() ) {
			$this->maybe_set_guest_cookie();
		}

		// Enqueue event tracker JavaScript.
		$tracker_handle = 'preco-event-tracker';
		AssetLoader::enqueue_script( $tracker_handle, 'preco-event-tracker', true );

		// Localize script with REST API configuration.
		AssetLoader::localize_script(
			$tracker_handle,
			'precoEventTracker',
			array(
				'restUrl'   => rest_url( 'preco/v1' ),
				'nonce'     => wp_create_nonce( 'wp_rest' ),
				'cartUrl'   => function_exists( 'wc_get_cart_url' ) ? wc_get_cart_url() : home_url( '/cart/' ),
				'isPreview' => PreviewMode::is_active_request(),
			)
		);

		// Enqueue recommendations slider JavaScript.
		AssetLoader::enqueue_script( 'preco-recommendations-slider', 'preco-recommendations-slider', true );

		// Row-position classes for wrapped grid cards (layout 3 divider lines).
		// Also loaded in the builder preview (class-admin.php) so both ends
		// render preco-common.css the same way.
		AssetLoader::enqueue_script( 'preco-grid-rows', 'preco-grid-rows', true );

		// Sequential display (Display Conditions) is a free feature — only the
		// After Delay / Page Reloads operators within it require an active
		// license, enforced server-side in LocationRenderer.
		AssetLoader::enqueue_script( 'preco-sequential-display', 'preco-sequential-display', true );

		// Pro-only assets: Popup Upsell and Order Bump never load without an
		// active license.
		if ( Preco::is_lc_active() ) {
			// Enqueue Popup Upsell trigger engine, only when at least one campaign exists.
			$popups = get_option( PopupUpsellRecommendations::OPTION_NAME, array() );
			if ( ! empty( $popups ) ) {
				// Depends on preco-event-tracker so precoEventTracker.cartUrl is
				// available for the view_cart_click trigger's href-matching fallback.
				AssetLoader::enqueue_script( 'preco-popup-upsell', 'preco-popup-upsell', true, array( 'preco-event-tracker' ) );
			}

			// Order Bump checkbox handler — checkout only, and only when at
			// least one campaign exists. The bump markup itself reuses the
			// already-enqueued recommendations slider for multi-product offers.
			$bumps = get_option( OrderBumpRecommendations::OPTION_NAME, array() );
			if ( ! empty( $bumps ) && function_exists( 'is_checkout' ) && \is_checkout() ) {
				AssetLoader::enqueue_script( 'preco-order-bump', 'preco-order-bump', true );
			}
		}
	}

	/**
	 * Build the global widget style CSS variables from the saved option,
	 * scoped to the recommendations wrapper.
	 *
	 * Mirrors generateGlobalCss()/generateGlobalCssText() in
	 * src/builder/utils/cssgenerator.js.
	 *
	 * @return string CSS text, or '' when nothing is saved.
	 */
	private function generate_global_css() {
		$global_styles = get_option( GlobalStylesRest::OPTION_NAME, array() );
		if ( ! is_array( $global_styles ) || empty( $global_styles ) ) {
			// Nothing saved yet — fall back to the same "classic" preset the
			// REST controller uses to fill in missing values, so the widget
			// still gets its intended default colors instead of none at all.
			$global_styles = GlobalStylesRest::COLOR_PRESETS['classic'];
		}

		$vars = array(
			'--preco-gs-button-bg-color'   => 'button_bg_color',
			'--preco-gs-button-text-color' => 'button_text_color',
			'--preco-gs-rating-color'      => 'rating_color',
			'--preco-gs-title-color'       => 'title_color',
			'--preco-gs-cat-color'         => 'cat_color',
			'--preco-gs-border-color'      => 'border_color',
			'--preco-gs-background-color'  => 'background_color',
		);

		$declarations = '';
		foreach ( $vars as $css_var => $option_key ) {
			$value = isset( $global_styles[ $option_key ] ) ? GlobalStylesRest::sanitize_hex_color_alpha( $global_styles[ $option_key ] ) : '';
			if ( $value ) {
				$declarations .= $css_var . ': ' . $value . '; ';
			}
		}

		return $declarations ? '.preco-recommendations { ' . trim( $declarations ) . ' }' : '';
	}

	/**
	 * Set a guest tracking cookie if not already set.
	 *
	 * @return void
	 */
	private function maybe_set_guest_cookie() {
		$cookie_name = 'preco_guest_id';

		if ( empty( $_COOKIE[ $cookie_name ] ) ) {
			$guest_id = wp_generate_uuid4();

			setcookie(
				$cookie_name,
				$guest_id,
				time() + ( 30 * DAY_IN_SECONDS ),
				( defined( 'COOKIEPATH' ) && COOKIEPATH ) ? COOKIEPATH : '/',
				COOKIE_DOMAIN,
				is_ssl(),
				true
			);

			$_COOKIE[ $cookie_name ] = $guest_id;
		}
	}
}
