<?php
namespace WooLentorPro;

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class Ajax_Action{

	/**
	 * [$instance]
	 * @var null
	 */
	private static $instance = null;

	/**
	 * [instance]
	 * @return [Ajax_Action]
	 */
    public static function instance(){
        if( is_null( self::$instance ) ){
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * [__construct]
     */
    function __construct(){
        // Execute the ajax function under init hook to work it properly,
        // prior to that hook cart quantity update via ajax won't work properly
        add_action( 'init', [ $this, 'load_ajax' ] );
    }

    public function load_ajax(){
        $this->quantity_update_action();
        $this->cart_page_qty_update_action();
        $this->cart_page_coupon_actions();
    }

    /**
     * Quantity Update Action
     *
     * @return void
     */
    public function quantity_update_action(){
        add_action( 'wp_ajax_nopriv_woolentor_update_cart_item_quantity', [ $this, 'update_cart_item_quantity' ] );
        add_action( 'wp_ajax_woolentor_update_cart_item_quantity',        [ $this, 'update_cart_item_quantity' ] );
    }

    /**
     * Register AJAX actions for cart-page style widgets (wl_cart_page_update_qty).
     * Must be registered here — admin-ajax.php never renders Elementor widgets,
     * so hooks added inside cart widget constructors never fire on AJAX requests.
     */
    public function cart_page_qty_update_action() {
        add_action( 'wp_ajax_wl_cart_page_update_qty',        [ $this, 'cart_page_update_qty' ] );
        add_action( 'wp_ajax_nopriv_wl_cart_page_update_qty', [ $this, 'cart_page_update_qty' ] );
    }

    /**
     * Handler for cart-page widgets.
     * Secured with nonce. Returns minimal JSON — cart-page JS re-fetches the page
     * for fresh HTML rather than patching the DOM with returned HTML.
     */
    public function cart_page_update_qty() {
        check_ajax_referer( 'wl-cart-page-nonce', 'nonce' );

        $cart_item_key = isset( $_POST['cart_item_key'] ) ? sanitize_text_field( wp_unslash( $_POST['cart_item_key'] ) ) : '';
        $qty           = isset( $_POST['qty'] ) ? wc_stock_amount( wp_unslash( $_POST['qty'] ) ) : 0;

        if ( ! $cart_item_key ) {
            wp_send_json_error( [ 'message' => esc_html__( 'Invalid cart item.', 'woolentor-pro' ) ] );
            return;
        }

        // Capture item data BEFORE removal so we can build the undo notice.
        $cart_item = WC()->cart->get_cart_item( $cart_item_key );

        $updated = $this->set_cart_item_quantity( $cart_item_key, $qty );

        if ( ! $updated ) {
            wp_send_json_error( [ 'message' => esc_html__( 'Could not update cart item.', 'woolentor-pro' ) ] );
            return;
        }

        $cart_empty   = WC()->cart->is_empty();
        $notices_html = '';

        if ( 0 === (int) $qty && $cart_item ) {
            $product  = $cart_item['data'];
            $undo_url = wc_get_cart_undo_url( $cart_item_key );
            wc_add_notice(
                sprintf(
                    wp_kses(
                        /* translators: %1$s product name, %2$s undo URL */
                        __( '&ldquo;%1$s&rdquo; removed. <a href="%2$s">Undo?</a>', 'woocommerce' ),
                        [ 'a' => [ 'href' => [] ] ]
                    ),
                    esc_html( apply_filters( 'woocommerce_cart_item_name', $product->get_name(), $cart_item, $cart_item_key ) ),
                    esc_url( $undo_url )
                ),
                'success'
            );

            // For non-empty cart: capture + clear the notice now and return the HTML directly.
            // This bypasses the race condition where the theme's hooks consume the session
            // notice before our widget's do_action( 'woocommerce_before_cart' ) fires.
            // For empty cart: leave the notice in the session — the full page reload will
            // render it naturally via woocommerce_before_cart / cart-empty template.
            if ( ! $cart_empty ) {
                ob_start();
                woocommerce_output_all_notices();
                $notices_html = ob_get_clean();
            }
        }

        wp_send_json_success( [
            'cart_hash'    => WC()->cart->get_cart_hash(),
            'cart_count'   => WC()->cart->get_cart_contents_count(),
            'cart_empty'   => $cart_empty,
            'notices_html' => $notices_html,
        ] );
    }

    /**
     * Handler for existing (legacy) widgets.
     * No nonce — matches original behaviour to avoid breaking changes.
     * Returns full item HTML data so callers can patch the DOM directly.
     */
    public function update_cart_item_quantity() {
        $qty           = absint( $_POST['qty'] );
        $cart_item_key = sanitize_key( $_POST['cart_item_key'] );

        $this->set_cart_item_quantity( $cart_item_key, $qty );

        $cart_item = WC()->cart->get_cart_item( $cart_item_key );

        // Item was removed (qty = 0) — nothing more to compute
        if ( ! $cart_item ) {
            wp_send_json( [ 'removed' => true ] );
            return;
        }

        $cart_product = $cart_item['data'];

        $product_price       = apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $cart_product ), $cart_item, $cart_item_key );
        $subtotal_price      = apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $cart_product, $cart_item['quantity'] ), $cart_item, $cart_item_key );
        $subtotal_price_html = $subtotal_price;

        $sale_price         = $cart_product->get_price();
        $regular_price      = $cart_product->get_regular_price();
        $regular_price_html = '';
        if ( $sale_price !== $regular_price ) {
            $regular_price      = $cart_product->get_regular_price() * $cart_item['quantity'];
            $regular_price_html = '<del class="woolentor-price-regular">' . wc_price( $regular_price ) . '</del>';
        }

        ob_start();
        WC()->cart->calculate_totals();
        woocommerce_cart_totals();
        $total_overview = ob_get_clean();

        wp_send_json( [
            'item_details'       => $cart_item,
            'item_price'         => $product_price,
            'item_subtotal_html' => $regular_price_html . $subtotal_price_html,
            'total_overview'     => $total_overview,
        ] );
    }

    /** Register coupon apply + remove actions. */
    public function cart_page_coupon_actions() {
        add_action( 'wp_ajax_wl_cart_apply_coupon',        [ $this, 'cart_page_apply_coupon' ] );
        add_action( 'wp_ajax_nopriv_wl_cart_apply_coupon', [ $this, 'cart_page_apply_coupon' ] );
        add_action( 'wp_ajax_wl_cart_remove_coupon',        [ $this, 'cart_page_remove_coupon' ] );
        add_action( 'wp_ajax_nopriv_wl_cart_remove_coupon', [ $this, 'cart_page_remove_coupon' ] );
    }

    /**
     * Apply a coupon code to the cart.
     * Expects POST: coupon_code.
     */
    public function cart_page_apply_coupon() {
        check_ajax_referer( 'wl-cart-page-nonce', 'nonce' );

        $code = isset( $_POST['coupon_code'] ) ? wc_format_coupon_code( sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) ) : '';

        if ( ! $code ) {
            wc_add_notice( WC_Coupon::get_generic_coupon_error( WC_Coupon::E_WC_COUPON_PLEASE_ENTER ), 'error' );
            ob_start();
            woocommerce_output_all_notices();
            $notices_html = ob_get_clean();
            wp_send_json_error( [ 'notices_html' => $notices_html ] );
            return;
        }

        WC()->cart->apply_coupon( $code );
        WC()->cart->calculate_totals();

        ob_start();
        woocommerce_output_all_notices();
        $notices_html = ob_get_clean();

        wp_send_json_success( [ 'notices_html' => $notices_html ] );
    }

    /**
     * Remove a coupon from the cart.
     * Expects POST: coupon_code.
     */
    public function cart_page_remove_coupon() {
        check_ajax_referer( 'wl-cart-page-nonce', 'nonce' );

        $code = isset( $_POST['coupon_code'] ) ? wc_format_coupon_code( sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) ) : '';

        if ( ! $code ) {
            wp_send_json_error( [ 'message' => esc_html__( 'Invalid coupon.', 'woolentor-pro' ) ] );
            return;
        }

        WC()->cart->remove_coupon( $code );
        wc_add_notice( __( 'Coupon has been removed.', 'woocommerce' ), 'success' );
        WC()->cart->calculate_totals();

        ob_start();
        woocommerce_output_all_notices();
        $notices_html = ob_get_clean();

        wp_send_json_success( [ 'notices_html' => $notices_html ] );
    }

    /**
     * Shared core: validate + update a single cart item quantity.
     * Returns false if the key is invalid. qty = 0 removes the item (WC default).
     *
     * @param  string     $cart_item_key
     * @param  int|float  $qty
     * @return bool
     */
    private function set_cart_item_quantity( $cart_item_key, $qty ) {
        if ( ! $cart_item_key ) {
            return false;
        }

        $item_exists = (bool) WC()->cart->get_cart_item( $cart_item_key );

        if ( 0 === (int) $qty ) {
            // remove_cart_item() stores the item in removed_cart_contents,
            // which WC's undo mechanism reads. set_quantity(0) does not.
            if ( $item_exists ) {
                WC()->cart->remove_cart_item( $cart_item_key );
            }
            return true;
        }

        if ( ! $item_exists ) {
            return false;
        }

        WC()->cart->set_quantity( $cart_item_key, $qty, true );
        return true;
    }
       
}

\WooLentorPro\Ajax_Action::instance();
