<?php
namespace Elementor;

if ( ! defined( 'ABSPATH' ) ) exit;

class Woolentor_Wl_Cart_Express_Checkout_Widget extends Widget_Base {

    public function __construct( $data = [], $args = null ) {
        parent::__construct( $data, $args );

        // Hook at priority 99 so WooCommerce and Stripe are fully bootstrapped.
        // The constructor runs during widget registration — before wp_enqueue_scripts —
        // so this add_action is guaranteed to land before that hook fires.
        add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_stripe_scripts' ], 99 );
    }

    public function get_name() {
        return 'wl-cart-express-checkout';
    }

    public function get_title() {
        return __( 'WL: Express Checkout', 'woolentor-pro' );
    }

    public function get_icon() {
        return 'woolentor-widget-new-icon eicon-stripe-button';
    }

    public function get_categories() {
        return [ 'woolentor-addons-pro' ];
    }

    public function get_help_url() {
        return 'https://woolentor.com/documentation/';
    }

    public function get_style_depends() {
        return [ 'woolentor-widgets-pro', 'wc_stripe_express_checkout_style' ];
    }

    public function get_script_depends() {
        return [ 'wc_stripe_express_checkout' ];
    }

    public function get_keywords() {
        return [ 'express checkout', 'apple pay', 'google pay', 'link', 'stripe', 'express payment', 'cart', 'checkout' ];
    }

    /**
     * Enqueues Stripe Express Checkout assets on cart/checkout pages.
     * Runs at wp_enqueue_scripts priority 99 — within the proper lifecycle,
     * after Stripe's own hooks have had a chance to fire first.
     */
    public function maybe_enqueue_stripe_scripts() {
        if ( is_admin() ) {
            return;
        }

        if ( ! is_cart() && ! is_checkout() ) {
            return;
        }

        $stripe_ece = $this->get_stripe_ece_instance();
        if ( ! $stripe_ece || is_string( $stripe_ece ) ) {
            return;
        }

        $this->register_and_enqueue_stripe_assets( $stripe_ece );

        // When a ShopLentor custom template is active, remove Stripe's default
        // display hooks so the widget exclusively controls button placement.
        // Without this, Stripe independently renders buttons at the top of the
        // page via woocommerce_checkout_before_customer_details / woocommerce_proceed_to_checkout,
        // causing double rendering and incorrect position.
        if ( $this->is_shoplentor_template_active() ) {
            remove_action( 'woocommerce_checkout_before_customer_details', [ $stripe_ece, 'display_express_checkout_button_html' ], 1 );
            remove_action( 'woocommerce_proceed_to_checkout',              [ $stripe_ece, 'display_express_checkout_button_html' ], 20 );
            remove_action( 'woocommerce_after_add_to_cart_form',           [ $stripe_ece, 'display_express_checkout_button_html' ], 1 );
        }
    }

    /**
     * Returns true when a ShopLentor custom template is active for the current page.
     * Used to decide whether to suppress Stripe's default button output hooks.
     */
    private function is_shoplentor_template_active() {
        if ( ! class_exists( 'Woolentor_Manage_WC_Template' ) ) {
            return false;
        }
        if ( is_checkout() && false !== \Woolentor_Manage_WC_Template::has_template( 'productcheckoutpage' ) ) {
            return true;
        }
        if ( is_cart() && false !== \Woolentor_Manage_WC_Template::has_template( 'productcartpage' ) ) {
            return true;
        }
        return false;
    }

    protected function register_controls() {

        /* ── Content: Settings ─────────────────────────────────────── */
        $this->start_controls_section(
            'express_checkout_settings',
            [
                'label' => __( 'Settings', 'woolentor-pro' ),
                'tab'   => Controls_Manager::TAB_CONTENT,
            ]
        );

            $this->add_control(
                'show_separator',
                [
                    'label'        => __( 'Show "OR" Separator', 'woolentor-pro' ),
                    'type'         => Controls_Manager::SWITCHER,
                    'label_on'     => __( 'Show', 'woolentor-pro' ),
                    'label_off'    => __( 'Hide', 'woolentor-pro' ),
                    'return_value' => 'yes',
                    'default'      => 'yes',
                    'description'  => __( 'Displays a separator below the express payment buttons.', 'woolentor-pro' ),
                ]
            );

            $this->add_control(
                'separator_text',
                [
                    'label'     => __( 'Separator Text', 'woolentor-pro' ),
                    'type'      => Controls_Manager::TEXT,
                    'default'   => __( 'OR', 'woolentor-pro' ),
                    'condition' => [ 'show_separator' => 'yes' ],
                ]
            );

            $this->add_control(
                'express_checkout_info',
                [
                    'type'         => Controls_Manager::NOTICE,
                    'notice_type'  => 'warning',
                    'dismissible'  => false,
                    'heading'      => esc_html__( 'Editor Preview Only', 'woolentor-pro' ),
                    'content'      => esc_html__( 'The buttons shown here are a demo preview. Actual Apple Pay, Google Pay, and Link buttons are rendered by Stripe on the frontend — they only appear on cart or checkout pages when Stripe Express Checkout is enabled in your Stripe settings.', 'woolentor-pro' ) . ' <a class="elementor-notice-link" target="_blank" href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout&section=stripe' ) ) . '">' . esc_html__( 'Configure Stripe Settings', 'woolentor-pro' ) . '</a>',
                ]
            );


        $this->end_controls_section();

        /* ── Style: Container ──────────────────────────────────────── */
        $this->start_controls_section(
            'express_checkout_container_style',
            [
                'label' => __( 'Container', 'woolentor-pro' ),
                'tab'   => Controls_Manager::TAB_STYLE,
            ]
        );

            $this->add_responsive_control(
                'container_padding',
                [
                    'label'      => __( 'Padding', 'woolentor-pro' ),
                    'type'       => Controls_Manager::DIMENSIONS,
                    'size_units' => [ 'px', 'em', '%' ],
                    'selectors'  => [
                        '{{WRAPPER}} .wl-express-checkout-wrap' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
                    ],
                ]
            );

            $this->add_responsive_control(
                'container_margin',
                [
                    'label'      => __( 'Margin', 'woolentor-pro' ),
                    'type'       => Controls_Manager::DIMENSIONS,
                    'size_units' => [ 'px', 'em', '%' ],
                    'selectors'  => [
                        '{{WRAPPER}} .wl-express-checkout-wrap' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
                    ],
                ]
            );

            $this->add_control(
                'container_bg_color',
                [
                    'label'     => __( 'Background Color', 'woolentor-pro' ),
                    'type'      => Controls_Manager::COLOR,
                    'selectors' => [
                        '{{WRAPPER}} .wl-express-checkout-wrap' => 'background-color: {{VALUE}};',
                    ],
                ]
            );

            $this->add_group_control(
                Group_Control_Border::get_type(),
                [
                    'name'     => 'container_border',
                    'selector' => '{{WRAPPER}} .wl-express-checkout-wrap',
                ]
            );

            $this->add_responsive_control(
                'container_border_radius',
                [
                    'label'      => __( 'Border Radius', 'woolentor-pro' ),
                    'type'       => Controls_Manager::DIMENSIONS,
                    'size_units' => [ 'px', 'em', '%' ],
                    'selectors'  => [
                        '{{WRAPPER}} .wl-express-checkout-wrap' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
                    ],
                ]
            );

            $this->add_group_control(
                Group_Control_Box_Shadow::get_type(),
                [
                    'name'     => 'container_box_shadow',
                    'selector' => '{{WRAPPER}} .wl-express-checkout-wrap',
                ]
            );

        $this->end_controls_section();

        /* ── Style: Separator ──────────────────────────────────────── */
        $this->start_controls_section(
            'express_checkout_separator_style',
            [
                'label'     => __( 'Separator', 'woolentor-pro' ),
                'tab'       => Controls_Manager::TAB_STYLE,
                'condition' => [ 'show_separator' => 'yes' ],
            ]
        );

            $this->add_group_control(
                Group_Control_Typography::get_type(),
                [
                    'name'     => 'separator_typography',
                    'selector' => '{{WRAPPER}} .wl-express-checkout-separator',
                ]
            );

            $this->add_control(
                'separator_color',
                [
                    'label'     => __( 'Text Color', 'woolentor-pro' ),
                    'type'      => Controls_Manager::COLOR,
                    'selectors' => [
                        '{{WRAPPER}} .wl-express-checkout-separator' => 'color: {{VALUE}};',
                    ],
                ]
            );

            $this->add_control(
                'separator_line_color',
                [
                    'label'     => __( 'Line Color', 'woolentor-pro' ),
                    'type'      => Controls_Manager::COLOR,
                    'default'   => '#d0d0d0',
                    'selectors' => [
                        '{{WRAPPER}} .wl-express-checkout-separator > span::before' => 'background: {{VALUE}};',
                        '{{WRAPPER}} .wl-express-checkout-separator > span::after'  => 'background: {{VALUE}};',
                    ],
                ]
            );

            $this->add_responsive_control(
                'separator_spacing',
                [
                    'label'      => __( 'Spacing (Top)', 'woolentor-pro' ),
                    'type'       => Controls_Manager::SLIDER,
                    'size_units' => [ 'px' ],
                    'range'      => [ 'px' => [ 'min' => 0, 'max' => 100 ] ],
                    'selectors'  => [
                        '{{WRAPPER}} .wl-express-checkout-separator' => 'margin-top: {{SIZE}}{{UNIT}};',
                    ],
                ]
            );

            $this->add_control(
                'separator_alignment',
                [
                    'label'     => __( 'Alignment', 'woolentor-pro' ),
                    'type'      => Controls_Manager::CHOOSE,
                    'options'   => [
                        'left'   => [ 'title' => __( 'Left', 'woolentor-pro' ),   'icon' => 'eicon-text-align-left' ],
                        'center' => [ 'title' => __( 'Center', 'woolentor-pro' ), 'icon' => 'eicon-text-align-center' ],
                        'right'  => [ 'title' => __( 'Right', 'woolentor-pro' ),  'icon' => 'eicon-text-align-right' ],
                    ],
                    'default'   => 'center',
                    'selectors' => [
                        '{{WRAPPER}} .wl-express-checkout-separator' => 'text-align: {{VALUE}};',
                    ],
                ]
            );

        $this->end_controls_section();
    }

    protected function render() {
        $settings = $this->get_settings_for_display();

        if ( Plugin::instance()->editor->is_edit_mode() ) {
            $this->render_editor_placeholder( $settings );
            return;
        }

        // Guard: widget only makes sense on cart or checkout pages.
        if ( ! is_cart() && ! is_checkout() ) {
            echo '<p class="wl-express-checkout-notice">'
                . esc_html__( 'Express Checkout only renders on the cart or checkout page.', 'woolentor-pro' )
                . '</p>';
            return;
        }

        $stripe_ece = $this->get_stripe_ece_instance();

        if ( is_string( $stripe_ece ) ) {
            // get_stripe_ece_instance() returned an error string
            echo '<p class="wl-express-checkout-notice">' . esc_html( $stripe_ece ) . '</p>';
            return;
        }

        // Safety net: if maybe_enqueue_stripe_scripts() didn't fire (edge-case where
        // the widget constructor ran after wp_enqueue_scripts), attempt a late enqueue.
        // Footer scripts are still flushed after page content, so this still lands correctly.
        $this->register_and_enqueue_stripe_assets( $stripe_ece );

        $sep_text = ! empty( $settings['separator_text'] ) ? $settings['separator_text'] : __( 'OR', 'woolentor-pro' );

        echo '<div class="wl-express-checkout-wrap">';

        // Skeleton loader — visible until Stripe mounts its buttons.
        echo '<div class="wl-express-checkout-skeleton" aria-hidden="true">';
        echo '<div class="wl-ece-skeleton-btn"></div>';
        echo '<div class="wl-ece-skeleton-btn"></div>';
        echo '</div>';

        // Capture Stripe's output and strip its internal separator.
        // display_express_checkout_button_html() calls display_express_checkout_button_separator_html()
        // internally, which only outputs on checkout pages. That creates a duplicate
        // #wc-stripe-express-checkout-button-separator element — Stripe's JS shows the
        // first one it finds (theirs), leaving our styled separator permanently hidden.
        ob_start();
        $stripe_ece->display_express_checkout_button_html();
        $stripe_html = ob_get_clean();
        $stripe_html = preg_replace(
            '/<p[^>]*\bid=["\']wc-stripe-express-checkout-button-separator["\'][^>]*>.*?<\/p>/s',
            '',
            $stripe_html
        );
        echo $stripe_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

        if ( 'yes' === $settings['show_separator'] ) {
            // ID must match what Stripe's ready event calls .show() on:
            //   getButtonSeparator: () => jQuery('#wc-stripe-express-checkout-button-separator')
            // Inner <span> lets CSS ::before/::after draw the horizontal lines.
            echo '<p class="wl-express-checkout-separator" id="wc-stripe-express-checkout-button-separator" style="display:none;">';
            echo '<span>' . esc_html( $sep_text ) . '</span>';
            echo '</p>';
        }

        // MutationObserver: hide skeleton when Stripe mounts its buttons (removes display:none
        // from #wc-stripe-express-checkout-element). Falls back to hiding after 5 s if Stripe
        // determines no payment methods are available on this device/browser.
        echo '<script>(function(){' .
             'var w=document.currentScript.parentElement;' .
             'var sk=w&&w.querySelector(".wl-express-checkout-skeleton");' .
             'var el=w&&w.querySelector("#wc-stripe-express-checkout-element");' .
             'if(!sk||!el)return;' .
             'function hide(){sk.style.display="none";}' .
             'var t=setTimeout(hide,5000);' .
             'var ob=new MutationObserver(function(){' .
             '  if(el.style.display!=="none"){ob.disconnect();clearTimeout(t);hide();}' .
             '});' .
             'ob.observe(el,{attributes:true,attributeFilter:["style"]});' .
             '})();</script>';

        echo '</div>';
    }

    /**
     * Returns the WC_Stripe_Express_Checkout_Element singleton, or an error string.
     *
     * @return \WC_Stripe_Express_Checkout_Element|string
     */
    private function get_stripe_ece_instance() {
        if ( ! class_exists( '\WC_Stripe_Express_Checkout_Element' ) ) {
            return __( 'Express Checkout requires the WooCommerce Stripe Gateway plugin to be installed and active.', 'woolentor-pro' );
        }

        $instance = \WC_Stripe_Express_Checkout_Element::instance();

        if ( ! $instance ) {
            return __( 'Express Checkout is not initialized. Ensure Stripe Express Checkout is enabled in Stripe → Settings.', 'woolentor-pro' );
        }

        return $instance;
    }

    /**
     * Registers, localizes, and enqueues all Stripe Express Checkout assets.
     *
     * Idempotent — safe to call multiple times; WordPress deduplicates enqueues.
     *
     * We must own the full registration here because Stripe's own scripts() method
     * (hooked at default wp_enqueue_scripts priority) may bail out via its internal
     * guards (SSL check, location settings, etc.) and never register the handle.
     * If that happens, wp_localize_script() on an unregistered handle silently fails.
     *
     * @param \WC_Stripe_Express_Checkout_Element $stripe_ece
     */
    private function register_and_enqueue_stripe_assets( $stripe_ece ) {
        // 1. Stripe.js CDN — required dependency for the express-checkout bundle.
        if ( ! wp_script_is( 'stripe', 'registered' ) ) {
            wp_register_script( 'stripe', 'https://js.stripe.com/clover/stripe.js', [], null, true );
        }

        // 2. Read the Webpack asset manifest for the hashed version + auto-generated deps.
        $asset_path = defined( 'WC_STRIPE_PLUGIN_PATH' ) ? WC_STRIPE_PLUGIN_PATH . '/build/express-checkout.asset.php' : '';
        $asset      = ( $asset_path && file_exists( $asset_path ) ) ? require $asset_path : [];
        $version    = $asset['version']      ?? ( defined( 'WC_STRIPE_VERSION' ) ? WC_STRIPE_VERSION : null );
        $deps       = $asset['dependencies'] ?? [];

        // 3. Register the express-checkout bundle if Stripe's own hooks didn't do it.
        if ( ! wp_script_is( 'wc_stripe_express_checkout', 'registered' ) ) {
            $plugin_url = defined( 'WC_STRIPE_PLUGIN_URL' ) ? WC_STRIPE_PLUGIN_URL : '';
            wp_register_script(
                'wc_stripe_express_checkout',
                $plugin_url . '/build/express-checkout.js',
                array_merge( [ 'jquery', 'stripe' ], $deps ),
                $version,
                true
            );
        }

        // 4. Localize JS params.
        //    We override three keys that would otherwise cause the bundle to bail:
        //
        //    has_block — modern WC stores <!-- wp:woocommerce/cart --> in post_content,
        //    so has_block('woocommerce/cart') returns true even on Elementor pages.
        //    The bundle's first line is: if (has_block && !is_pay_for_order) return;
        //    Forcing false tells it to use the legacy (non-block) init path.
        //
        //    is_cart_page / is_checkout_page — re-evaluated fresh here so they always
        //    reflect the live request, not any cached value from Stripe's earlier hook.
        if ( method_exists( $stripe_ece, 'javascript_params' ) ) {
            $params = apply_filters(
                'wc_stripe_express_checkout_params',
                $stripe_ece->javascript_params()
            );

            $params['has_block']        = false;
            $params['is_cart_page']     = is_cart();
            $params['is_checkout_page'] = is_checkout();

            // Allow third-party code to modify params before they reach the JS bundle.
            $params = apply_filters( 'woolentor/express_checkout/params', $params );

            wp_localize_script( 'wc_stripe_express_checkout', 'wc_stripe_express_checkout_params', $params );
        }

        // 5. Enqueue companion stylesheet.
        if ( ! wp_style_is( 'wc_stripe_express_checkout_style', 'enqueued' ) ) {
            $plugin_url = defined( 'WC_STRIPE_PLUGIN_URL' ) ? WC_STRIPE_PLUGIN_URL : '';
            wp_enqueue_style( 'wc_stripe_express_checkout_style', $plugin_url . '/build/express-checkout.css', [], $version );
        }

        // 6. Enqueue the script (no-op if already enqueued).
        wp_enqueue_script( 'wc_stripe_express_checkout' );
    }

    private function render_editor_placeholder( $settings ) {
        $sep_text = ! empty( $settings['separator_text'] ) ? $settings['separator_text'] : __( 'OR', 'woolentor-pro' );

        $buttons = [
            [ 'label' => 'Apple Pay',   'bg' => '#000000', 'color' => '#ffffff' ],
            [ 'label' => 'Google Pay',  'bg' => '#000000', 'color' => '#ffffff' ],
            [ 'label' => '❯ link',      'bg' => '#33CC66', 'color' => '#ffffff' ],
        ];

        echo '<div class="wl-express-checkout-wrap wl-express-checkout-preview">';

        foreach ( $buttons as $btn ) {
            printf(
                '<div class="wl-express-btn-placeholder" style="background-color:%s;color:%s;">%s</div>',
                esc_attr( $btn['bg'] ),
                esc_attr( $btn['color'] ),
                esc_html( $btn['label'] )
            );
        }

        if ( 'yes' === $settings['show_separator'] ) {
            echo '<p class="wl-express-checkout-separator"><span>' . esc_html( $sep_text ) . '</span></p>';
        }

        echo '</div>';
    }

}
