<?php

/**
 * Main plugin orchestrator.
 *
 * @package CartGiftWrapping
 */
defined( 'ABSPATH' ) || exit;
/**
 * Class CGWFW_Plugin
 *
 * Wires together settings, assets and the cart behaviour.
 */
final class CGWFW_Plugin {
    /**
     * Singleton instance.
     *
     * @var CGWFW_Plugin|null
     */
    private static $instance = null;

    /**
     * Settings handler.
     *
     * @var CGWFW_Settings
     */
    public $settings;

    /**
     * Cart handler.
     *
     * @var CGWFW_Cart
     */
    public $cart;

    /**
     * Product-page handler.
     *
     * @var CGWFW_Product
     */
    public $product;

    /**
     * Third-party compatibility shims (e.g. WP Rocket).
     *
     * @var CGWFW_Compat
     */
    public $compat;

    /**
     * Get the singleton instance.
     *
     * @return CGWFW_Plugin
     */
    public static function instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor.
     */
    private function __construct() {
        $this->settings = new CGWFW_Settings();
        $this->cart = new CGWFW_Cart($this->settings);
        $this->compat = new CGWFW_Compat();
        add_action( 'wp_enqueue_scripts', array($this, 'enqueue_frontend_assets') );
        add_action( 'admin_enqueue_scripts', array($this, 'enqueue_admin_assets') );
        add_filter( 'plugin_action_links_' . CGWFW_BASENAME, array($this, 'plugin_action_links') );
        add_filter(
            'plugin_row_meta',
            array($this, 'plugin_row_meta'),
            10,
            2
        );
        add_action( 'woocommerce_blocks_loaded', array($this, 'register_blocks_integration') );
    }

    /**
     * Register the Cart & Checkout Blocks integration and the Store API data
     * it relies on. Runs only when WooCommerce Blocks is available.
     *
     * @return void
     */
    public function register_blocks_integration() {
        if ( !interface_exists( 'Automattic\\WooCommerce\\Blocks\\Integrations\\IntegrationInterface' ) ) {
            return;
        }
        require_once CGWFW_PATH . 'includes/class-cgwfw-blocks-integration.php';
        $settings = $this->settings;
        $cart = $this->cart;
        // Enqueue our script/style onto the Cart and Checkout blocks.
        $register = function ( $registry ) use($settings, $cart) {
            $registry->register( new CGWFW_Blocks_Integration($settings, $cart) );
        };
        add_action( 'woocommerce_blocks_cart_block_registration', $register );
        add_action( 'woocommerce_blocks_checkout_block_registration', $register );
        // Expose live wrap state + fee to the front end via the cart schema.
        if ( function_exists( 'woocommerce_store_api_register_endpoint_data' ) ) {
            woocommerce_store_api_register_endpoint_data( array(
                'endpoint'        => 'cart',
                'namespace'       => 'cart-gift-wrapping',
                'data_callback'   => function () use($settings, $cart) {
                    $state = $cart->get_order_state();
                    return array(
                        'enabled'   => !empty( $state['enabled'] ),
                        'message'   => ( isset( $state['message'] ) ? (string) $state['message'] : '' ),
                        'option'    => ( isset( $state['option'] ) ? (string) $state['option'] : '' ),
                        'available' => $cart->has_eligible_item(),
                        'fee_html'  => wp_strip_all_tags( wc_price( $settings->get_fee() ) ),
                    );
                },
                'schema_callback' => function () {
                    return array(
                        'enabled'   => array(
                            'description' => __( 'Whether order gift wrapping is enabled.', 'tinyplugs-gift-wrapping' ),
                            'type'        => 'boolean',
                            'readonly'    => true,
                        ),
                        'message'   => array(
                            'description' => __( 'The gift message for the order.', 'tinyplugs-gift-wrapping' ),
                            'type'        => 'string',
                            'readonly'    => true,
                        ),
                        'option'    => array(
                            'description' => __( 'The selected wrap design id.', 'tinyplugs-gift-wrapping' ),
                            'type'        => 'string',
                            'readonly'    => true,
                        ),
                        'available' => array(
                            'description' => __( 'Whether the cart has an item eligible for wrapping.', 'tinyplugs-gift-wrapping' ),
                            'type'        => 'boolean',
                            'readonly'    => true,
                        ),
                        'fee_html'  => array(
                            'description' => __( 'The formatted wrapping fee.', 'tinyplugs-gift-wrapping' ),
                            'type'        => 'string',
                            'readonly'    => true,
                        ),
                    );
                },
                'schema_type'     => ARRAY_A,
            ) );
        }
        // Receive toggle/message changes from the block UI.
        if ( function_exists( 'woocommerce_store_api_register_update_callback' ) ) {
            woocommerce_store_api_register_update_callback( array(
                'namespace' => 'cart-gift-wrapping',
                'callback'  => function ( $data ) use($cart) {
                    $enabled = !empty( $data['enabled'] );
                    $message = ( isset( $data['message'] ) ? (string) $data['message'] : '' );
                    $option = ( isset( $data['option'] ) ? (string) $data['option'] : '' );
                    $cart->set_order_state( $enabled, $message, $option );
                },
            ) );
        }
    }

    /**
     * Detect whether the Cart page uses the WooCommerce Cart block.
     *
     * The per-item button relies on classic-cart PHP hooks, which the block
     * cart ignores, so we warn the merchant when that is the case.
     *
     * @return bool
     */
    public function cart_uses_block() {
        if ( !function_exists( 'wc_get_page_id' ) ) {
            return false;
        }
        $cart_page_id = wc_get_page_id( 'cart' );
        if ( $cart_page_id <= 0 ) {
            return false;
        }
        $page = get_post( $cart_page_id );
        if ( !$page ) {
            return false;
        }
        return has_block( 'woocommerce/cart', $page );
    }

    /**
     * Add a Settings link on the plugins list.
     *
     * @param array $links Existing action links.
     * @return array
     */
    public function plugin_action_links( $links ) {
        $settings_link = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'admin.php?page=wc-settings&tab=cgwfw' ) ), esc_html__( 'Settings', 'tinyplugs-gift-wrapping' ) );
        array_unshift( $links, $settings_link );
        return $links;
    }

    /**
     * Add "Visit plugin site" (and, in Pro, "Support") links to the plugin's
     * row meta on the plugins list. Core replaces its own "Visit plugin site"
     * link with "View details" once update data exists (via Freemius), so we
     * add the site link back explicitly.
     *
     * @param array  $links Existing row meta links.
     * @param string $file  Plugin basename the row belongs to.
     * @return array
     */
    public function plugin_row_meta( $links, $file ) {
        if ( CGWFW_BASENAME !== $file ) {
            return $links;
        }
        $links[] = sprintf( '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url( 'https://www.tinyplugs.com/plugins/gift-wrapping-for-woocommerce-cart-checkout/' ), esc_html__( 'Visit plugin site', 'tinyplugs-gift-wrapping' ) );
        if ( $this->settings->is_pro() ) {
            $links[] = sprintf( '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url( 'https://www.tinyplugs.com/support/' ), esc_html__( 'Support', 'tinyplugs-gift-wrapping' ) );
        }
        return $links;
    }

    /**
     * Enqueue the settings-page script that shows/hides fields by mode.
     *
     * @param string $hook_suffix Current admin page hook.
     * @return void
     */
    public function enqueue_admin_assets( $hook_suffix ) {
        if ( 'woocommerce_page_wc-settings' !== $hook_suffix ) {
            return;
        }
        // The ignore must sit on its own line: the Freemius build processor
        // relocates trailing comments, which detaches a same-line ignore.
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only tab check on the WC settings screen; no form data is processed.
        if ( !isset( $_GET['tab'] ) || 'cgwfw' !== $_GET['tab'] ) {
            return;
        }
        // Needed for the wrap-design image picker.
        wp_enqueue_media();
        wp_enqueue_script(
            'cgwfw-admin',
            CGWFW_URL . 'assets/js/cgwfw-admin.js',
            array('jquery'),
            CGWFW_VERSION,
            true
        );
        wp_localize_script( 'cgwfw-admin', 'cgwfwAdmin', array(
            'cartUsesBlock'       => $this->cart_uses_block(),
            'blockWarning'        => __( 'Your Cart page uses the WooCommerce Cart block, which has no per-item control, so per-item wrapping will not appear there. Switch to "Per order" (works on the block cart) or use the classic [woocommerce_cart] and [woocommerce_checkout] shortcodes.', 'tinyplugs-gift-wrapping' ),
            'productBlockWarning' => __( 'Your Cart page uses the WooCommerce Cart block. Customers can still choose gift wrapping on the product page and it is charged and saved to the order, but the block cart will not show it or let them change it. For full control in the cart, use the classic [woocommerce_cart] and [woocommerce_checkout] shortcodes.', 'tinyplugs-gift-wrapping' ),
            'mediaTitle'          => __( 'Select wrap image', 'tinyplugs-gift-wrapping' ),
            'mediaButton'         => __( 'Use image', 'tinyplugs-gift-wrapping' ),
        ) );
    }

    /**
     * Enqueue front-end CSS/JS on the cart and checkout only.
     *
     * @return void
     */
    public function enqueue_frontend_assets() {
        if ( !function_exists( 'is_cart' ) ) {
            return;
        }
        $on_cart_checkout = is_cart() || is_checkout();
        $on_product = function_exists( 'is_product' ) && is_product() && $this->settings->product_page_enabled();
        if ( !$on_cart_checkout && !$on_product ) {
            return;
        }
        wp_enqueue_style(
            'cgwfw',
            CGWFW_URL . 'assets/css/cgwfw.css',
            array(),
            CGWFW_VERSION
        );
        // Inject the admin-configured button styling as CSS variables.
        wp_add_inline_style( 'cgwfw', $this->settings->get_inline_css() );
        // The flat-fee product-page control is a plain form field (no AJAX),
        // but the design pickers (dropdown/lightbox) are script-driven, so the
        // front-end script is also needed on product pages in design mode.
        if ( !$on_cart_checkout && !$this->settings->has_wrap_options() ) {
            return;
        }
        wp_enqueue_script(
            'cgwfw',
            CGWFW_URL . 'assets/js/cgwfw.js',
            array('jquery'),
            CGWFW_VERSION,
            true
        );
        wp_localize_script( 'cgwfw', 'cgwfwData', array(
            'ajaxUrl'       => admin_url( 'admin-ajax.php' ),
            'nonce'         => wp_create_nonce( 'cgwfw_toggle' ),
            'label'         => $this->settings->get( 'button_label' ),
            'labelAdded'    => $this->settings->get( 'button_label_added' ),
            'messageLabel'  => $this->settings->get( 'message_label' ),
            'enableMessage' => 'yes' === $this->settings->get( 'enable_message' ),
            'messageLimit'  => (int) $this->settings->get( 'message_limit' ),
        ) );
    }

}
