<?php
/**
 * Buttons class.
 *
 * @package SaveToWishlist\Classes\Frontend
 * @since 1.0.0
 */
namespace SaveToWishlist\Classes\Frontend;

use SaveToWishlist\Abstracts\Singleton;
use SaveToWishlist\Helpers\Vite_App;
use SaveToWishlist\Helpers\Helper_Functions;
use SaveToWishlist\Classes\Frontend\Buttons;
use SaveToWishlist\Classes\Translations;
use SaveToWishlist\Classes\Frontend\Wishlist;

// Integrations Classes.
use SaveToWishlist\Classes\Integrations\Pro_Dependencies;

/**
 * Class Frontend_Hooks
 *
 * This class serves as the main plugin class.
 */
class Frontend_Hooks extends Singleton {

    /**
     * Helper functions.
     *
     * @var Helper_Functions
     */
    private $helper_functions;

    /**
     * Buttons.
     *
     * @var Buttons
     */
    private $buttons;

    /**
     * Wishlist.
     *
     * @var Wishlist
     */
    private $wishlist;

    /**
     * Constructor.
     *
     * @since 1.0.0
     * @access public
     */
    public function __construct() {
        $this->helper_functions = Helper_Functions::instance();
        $this->buttons          = Buttons::instance();
        $this->wishlist         = Wishlist::instance();
    }

    /**
     * Run the controller.
     *
     * @since 1.0.0
     * @access public
     */
    public function run() {
        add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts_and_styles' ) );

        // Add rewrite rules.
        add_action( 'init', array( $this, 'add_my_account_wishlist_endpoint' ) );
        add_action( 'init', array( $this->wishlist, 'add_rewrite_rules' ) );
        add_filter( 'query_vars', array( $this->wishlist, 'add_query_vars' ) );

        // Add Wishlist tab to My Account page.
        add_action( 'init', array( $this, 'show_wishlist_in_my_account_page' ) );

        // Display wishlist button on shop and product pages.
        $this->buttons->display_wishlist_button_on_shop_page();
        $this->buttons->display_wishlist_button_on_product_page();
        $this->buttons->display_wishlist_button_on_cart_page();

        // Add shortcode.
        add_shortcode( 'saveto_wishlist', array( $this->wishlist, 'saveto_wishlist_shortcodes' ) );

        // Display wishlist content.
        add_action( 'template_redirect', array( $this->wishlist, 'display_wishlist_rewrite_content' ) );

        // Wishlist Filters.
        add_filter( 'stwlite_collections_where', array( $this->wishlist, 'show_public_wishlist' ), 10, 1 );

        // Add to cart.
        add_action( 'wp_ajax_stwlite_add_to_cart', array( $this->wishlist, 'add_to_cart' ) );
        add_action( 'wp_ajax_nopriv_stwlite_add_to_cart', array( $this->wishlist, 'add_to_cart' ) );

        // Add to wishlist.
        add_action( 'wp_ajax_stwlite_add_to_wishlist', array( $this->wishlist, 'add_to_wishlist' ) );
        add_action( 'wp_ajax_nopriv_stwlite_add_to_wishlist', array( $this->wishlist, 'add_to_wishlist' ) );

        // Check if product is in wishlist.
        add_action( 'wp_ajax_stwlite_check_product_in_wishlist', array( $this->wishlist, 'check_product_in_wishlist' ) );
        add_action( 'wp_ajax_nopriv_stwlite_check_product_in_wishlist', array( $this->wishlist, 'check_product_in_wishlist' ) );

        // Add product cart to wishlist.
        add_action( 'wp_ajax_stwlite_add_product_cart_to_wishlist', array( $this->wishlist, 'add_product_cart_to_wishlist' ) );
        add_action( 'wp_ajax_nopriv_stwlite_add_product_cart_to_wishlist', array( $this->wishlist, 'add_product_cart_to_wishlist' ) );

        // Remove product from wishlist.
        add_action( 'wp_ajax_stwlite_remove_product_from_wishlist', array( $this->wishlist, 'remove_product_from_wishlist' ) );
        add_action( 'wp_ajax_nopriv_stwlite_remove_product_from_wishlist', array( $this->wishlist, 'remove_product_from_wishlist' ) );

        // Store wishlist from localStorage to database after account is created/logged in.
        add_action( 'wp_ajax_stwlite_store_wishlist_from_local_storage', array( $this->wishlist, 'store_wishlist_from_local_storage' ) );
        add_action( 'wp_ajax_nopriv_stwlite_store_wishlist_from_local_storage', array( $this->wishlist, 'store_wishlist_from_local_storage' ) );

        // Create wishlist if no wishlist exists.
        add_filter( 'stwlite_response_wishlist_data', array( $this->wishlist, 'auto_create_wishlist' ), 10, 2 );

        // Flush rewrite rules when WPML language is switched.
        add_action( 'wpml_language_switched', array( $this->helper_functions, 'flush_rewrite_rules' ) );
    }

    /**
     * Show Wishlist in My Account page.
     *
     * @since 1.0.0
     * @access public
     */
    public function show_wishlist_in_my_account_page() {
        $disable_my_account_page = get_option( 'stwlite_settings_disable_my_account_page', 'no' );

        if ( is_user_logged_in() && 'yes' !== $disable_my_account_page ) {
            add_filter( 'woocommerce_account_menu_items', array( $this, 'add_wishlist_menu_item' ) );
            add_action( 'woocommerce_account_wishlist_endpoint', array( $this, 'add_wishlist_menu_item_content' ) );
        }
    }

    /**
     * Add Wishlist tab to My Account page.
     *
     * @param array $items The menu items.
     * @return array The menu items.
     */
    public function add_wishlist_menu_item( $items ) {
        // Insert wishlist tab right after orders tab.
        $reordered_items = array();

        foreach ( $items as $key => $value ) {
            $reordered_items[ $key ] = $value;

            // Insert wishlist after orders.
            if ( 'orders' === $key ) {
                $reordered_items['wishlist'] = __( 'Wishlists', 'saveto-wishlist-lite-for-woocommerce' );
            }
        }

        return $reordered_items;
    }

    /**
     * Add Wishlist tab content to My Account page.
     *
     * @since 1.0.0
     * @access public
     */
    public function add_wishlist_menu_item_content() {
        echo do_shortcode( '[saveto_wishlist]' );
    }

    /**
     * Add My Account Wishlist endpoint.
     *
     * @since 1.0.0
     * @access public
     */
    public function add_my_account_wishlist_endpoint() {
        add_rewrite_endpoint( 'wishlist', EP_PAGES );
    }

    /**
     * Frontend scripts and styles.
     *
     * @since 1.0.0
     * @access public
     */
    public function frontend_scripts_and_styles() {
        // Register styles based on the configured CSS loading mode.
        $css_mode      = get_option( 'stwlite_settings_frontend_css_mode', 'full' );
        $css_filenames = array(
            'full'    => 'savetowishlist-frontend-styles.css',
            'minimal' => 'savetowishlist-frontend-styles-minimal.css',
            'none'    => 'savetowishlist-frontend-styles-positions.css',
        );
        $css_filename  = isset( $css_filenames[ $css_mode ] ) ? $css_filenames[ $css_mode ] : $css_filenames['full'];

        wp_enqueue_style( 'stwlite_frontend_css', STWLITE_CSS_URL . $css_filename, array(), STWLITE_VERSION, 'all' );
        // Register scripts.
        wp_enqueue_script( 'stwlite_frontend_js', STWLITE_JS_URL . 'savetowishlist-frontend-scripts.js', array( 'jquery' ), STWLITE_VERSION, true );

        $translations = Translations::instance()->frontend_translations();
        wp_localize_script(
            'stwlite_frontend_js',
            'stwlite_frontend_js_vars',
            array(
                'ajax_url'       => admin_url( 'admin-ajax.php' ),
                'nonce'          => wp_create_nonce( 'stwlite_frontend_nonce' ),
                'api_url'        => rest_url( 'saveto-wishlist/v1/frontend/endpoints' ),
                'i18n'           => $translations,
                'stwOptions'     => $this->wishlist->get_wishlist_options(),
                'user_id'        => get_current_user_id(),
                'buttonLabels'   => array(
                    'shopWishlistLabel'         => $this->buttons->shop_wishlist_button_label_option(),
                    'selectedShopWishlistLabel' => $this->buttons->selected_wishlist_button_label_option(),
                ),
                // Pre-generated button HTML for each cart item, consumed by the
                // MutationObserver in the frontend JS to inject buttons into the
                // WooCommerce block cart (which renders items client-side via React).
                'blockCartItems' => is_cart() ? $this->buttons->get_block_cart_item_buttons() : array(),
            )
        );

        // Check if the shortcode is used in the page or the wishlist page or the my account page.
        if ( has_shortcode( get_the_content(), 'saveto_wishlist' ) || is_page( get_option( 'stwlite_wishlist_page' ) ) || is_account_page() ) {
            $show_for_admin = apply_filters( 'stwlite_show_all_wishlists_for_admin', false );
            $user_role      = is_user_logged_in() ? wp_get_current_user()->roles[0] : 'guest';
            if ( $show_for_admin && current_user_can( 'administrator' ) ) { // phpcs:ignore
                $user_role = 'admin';
            }

            $wishlists_object = array(
                'i18n'                 => $translations,
                'wishlistOptions'      => $this->wishlist->get_wishlist_options(),
                'wpNonce'              => wp_create_nonce( 'wp_rest' ),
                'restApiUrl'           => rest_url( 'saveto-wishlist/v1/frontend/endpoints' ),
                'usersApiUrl'          => rest_url( 'wp/v2/users' ),
                'user_id'              => is_user_logged_in() ? get_current_user_id() : 0,
                'user_role'            => $user_role,
                'user_email'           => is_user_logged_in() ? wp_get_current_user()->user_email : '',
                'isLoggedIn'           => is_user_logged_in(),
                'selectedWishlist'     => $this->wishlist->get_wishlist_by_code(),
                'selectedWishlistCode' => $this->wishlist->get_wishlist_code(),
                'wcCurrency'           => $this->helper_functions->get_wc_currency(),
                'pageUrls'             => array(
                    'shopUrl'      => get_permalink( wc_get_page_id( 'shop' ) ),
                    'myAccountUrl' => get_permalink( get_option( 'woocommerce_myaccount_page_id' ) ),
                    'wishlistUrl'  => get_permalink( get_option( 'stwlite_wishlist_page' ) ),
                ),
                'ajax'                 => array(
                    'url'                => admin_url( 'admin-ajax.php' ),
                    'nonce'              => wp_create_nonce( 'stwlite_frontend_nonce' ),
                    'getDefaultWishlist' => $this->wishlist->get_default_wishlist(),
                ),
                'wishlistsAsOptions'   => $this->wishlist->get_wishlists_as_options(),
                'proDependencies'      => Pro_Dependencies::instance()->get_pro_dependencies(),
                'pageStyles'           => $this->get_wishlist_app_page_styles( $css_mode ),
            );
            $wishlists_app    = new Vite_App(
                'saveto-wishlist-frontend-app-scripts',
                'src/apps/frontend/index.ts',
                array(
                    'wp-i18n',
                    'wp-url',
                    'wp-hooks',
                    'wp-html-entities',
                    'lodash',
                    'jquery',
                ),
                array(),
                $wishlists_object
            );
            $wishlists_app->enqueue();

            // In "none" mode, keep the Vue wishlist app's bundled CSS
            // (so positions and layout stay intact) but neutralize the
            // decorative properties (color, background, shadow, border
            // color, font family and font size) on the app's elements
            // so the active theme's text color, background and font
            // cascade through. In "minimal" mode the bundled CSS loads
            // unchanged — its decorative properties do not use
            // `!important`, so themes can override colors and fonts
            // through normal CSS specificity. In both "minimal" and
            // "none" modes the inline `:style` color and `fontSize`
            // bindings in the Vue templates are blanked out via
            // `get_wishlist_app_page_styles()`; otherwise those inline
            // styles would outweigh theme stylesheet rules.
            if ( 'none' === $css_mode ) {
                wp_add_inline_style(
                    'saveto-wishlist-frontend-app-scripts',
                    $this->get_wishlist_app_theme_adaptive_css()
                );
            }
        }
    }

    /**
     * Inline CSS that neutralizes the Vue wishlist app's decorative
     * properties so colors, backgrounds, shadows and typography sizes
     * fall through to the active theme.
     *
     * Applies directly to the consuming declarations (`color`,
     * `background-color`, `background-image`, `box-shadow`,
     * `border-color`, `font-family`, `font-size`) on the Vue app's host
     * elements and all descendants. This sidesteps a cascade pitfall
     * with overriding custom properties via `inherit`: at `:root` the
     * variable has no parent value and falls back to the consuming
     * `var()`'s fallback, which is itself a still-defined plugin color.
     * Overriding the consuming properties directly avoids that chain.
     *
     * Positions, padding, dimensions and border radii are sourced from
     * `savetowishlist-frontend-styles-positions.css` and are not
     * touched here.
     *
     * @since 1.0.6
     * @access private
     * @return string
     */
    private function get_wishlist_app_theme_adaptive_css() {
        return implode(
            '',
            array(
                '#saveto-wishlist-app,#saveto-wishlist-app *,',
                'saveto-wishlist,saveto-wishlist *,',
                'saveto-wishlist-item,saveto-wishlist-item *,',
                'saveto-wishlist-guest,saveto-wishlist-guest *{',
                'color:inherit !important;',
                'background-color:transparent !important;',
                'background-image:none !important;',
                'box-shadow:none !important;',
                'border-color:currentColor !important;',
                'font-family:inherit !important;',
                'font-size:inherit !important;',
                '}',
            )
        );
    }

    /**
     * Build the `pageStyles` payload exposed to the Vue wishlist app.
     *
     * In "minimal" and "none" modes the configurable color, background
     * and typography size values are blanked out. Vue's `:style`
     * bindings skip empty color values and the browser ignores invalid
     * `font-size: px` declarations produced by the blank numeric
     * values, so no inline appearance or sizing is written. Without
     * those inline-style bindings (which would otherwise outweigh
     * stylesheet rules without `!important`) the active theme's CSS
     * can override the wishlist page UI via normal cascade.
     * `showProductImage` is a structural toggle and is preserved
     * across all modes.
     *
     * @since 1.0.6
     * @access private
     *
     * @param string $css_mode Active "Frontend CSS Loading" mode.
     * @return array
     */
    private function get_wishlist_app_page_styles( $css_mode ) {
        $page_styles = array(
            'headingTitleSize'                 => get_option( 'stwlite_settings_wishlist_page_heading_title_size', 28 ),
            'headingTitleColor'                => get_option( 'stwlite_settings_wishlist_page_heading_title_color', '#000000' ),
            'headingTextSize'                  => get_option( 'stwlite_settings_wishlist_page_heading_text_size', 14 ),
            'headingTextColor'                 => get_option( 'stwlite_settings_wishlist_page_heading_text_color', '#000000' ),
            'tableColumnTextSize'              => get_option( 'stwlite_settings_wishlist_page_table_column_text_size', 14 ),
            'tableRowTextSize'                 => get_option( 'stwlite_settings_wishlist_page_table_row_text_size', 14 ),
            'buttonTextSize'                   => get_option( 'stwlite_settings_wishlist_page_button_text_size', 14 ),
            'buttonTextColor'                  => get_option( 'stwlite_settings_wishlist_page_button_text_color', '#FFFFFF' ),
            'buttonBackgroundColor'            => get_option( 'stwlite_settings_wishlist_page_button_background_color', '#3B82F6' ),
            'popupTitleSize'                   => get_option( 'stwlite_settings_wishlist_page_popup_title_size', 32 ),
            'popupTitleColor'                  => get_option( 'stwlite_settings_wishlist_page_popup_title_color', '#000000' ),
            'popupTextSize'                    => get_option( 'stwlite_settings_wishlist_page_popup_text_size', 14 ),
            'popupTextColor'                   => get_option( 'stwlite_settings_wishlist_page_popup_text_color', '#000000' ),
            'popupButtonTextSize'              => get_option( 'stwlite_settings_wishlist_page_popup_button_text_size', 14 ),
            'popupSaveButtonTextColor'         => get_option( 'stwlite_settings_wishlist_page_popup_save_button_text_color', '#FFFFFF' ),
            'popupSaveButtonBackgroundColor'   => get_option( 'stwlite_settings_wishlist_page_popup_save_button_background_color', '#3B82F6' ),
            'popupCancelButtonTextColor'       => get_option( 'stwlite_settings_wishlist_page_popup_cancel_button_text_color', '#FFFFFF' ),
            'popupCancelButtonBackgroundColor' => get_option( 'stwlite_settings_wishlist_page_popup_cancel_button_background_color', '#EF4444' ),
            'showProductImage'                 => 'yes' === get_option( 'stwlite_settings_wishlist_page_show_product_image', 'yes' ),
        );

        if ( 'full' === $css_mode ) {
            return $page_styles;
        }

        foreach ( $page_styles as $key => $value ) {
            if ( 'showProductImage' === $key ) {
                continue;
            }
            $page_styles[ $key ] = '';
        }

        return $page_styles;
    }
}
