<?php

/**
 * The public-facing functionality of the plugin.
 *
 * Handles front-end script/style enqueuing, WooCommerce template
 * overrides, mystery box opening logic (AJAX), reward selection,
 * order creation, and My Account integration.
 *
 * @link       https://wpgenie.org
 * @since      1.0.0
 *
 * @package    Mysterx
 * @subpackage Mysterx/public
 */
/**
 * Class Mysterx_Public
 *
 * @since 1.0.0
 */
class Mysterx_Public {
    /**
     * The ID of this plugin.
     *
     * @since    1.0.0
     * @access   private
     * @var      string    $plugin_name    The ID of this plugin.
     */
    private $plugin_name;

    /**
     * The version of this plugin.
     *
     * @since    1.0.0
     * @access   private
     * @var      string    $version    The current version of this plugin.
     */
    private $version;

    /**
     * Initialize the class and set its properties.
     *
     * @since    1.0.0
     * @param      string $plugin_name       The name of the plugin.
     * @param      string $version    The version of this plugin.
     */
    public function __construct( $plugin_name, $version ) {
        $this->plugin_name = $plugin_name;
        $this->version = $version;
    }

    /**
     * Register the stylesheets for the public-facing side of the site.
     *
     * @since    1.0.0
     */
    public function enqueue_styles() {
        /**
         * This function is provided for demonstration purposes only.
         *
         * An instance of this class should be passed to the run() function
         * defined in Mysterx_Loader as all of the hooks are defined
         * in that particular class.
         *
         * The Mysterx_Loader will then create the relationship
         * between the defined hooks and the functions defined in this
         * class.
         */
        wp_enqueue_style(
            $this->plugin_name,
            plugin_dir_url( __FILE__ ) . 'css/mysterx-public.css',
            array(),
            $this->version,
            'all'
        );
    }

    /**
     * Register the JavaScript for the public-facing side of the site.
     *
     * @since    1.0.0
     */
    public function enqueue_scripts() {
        $options = get_option( 'mysterx_options', array() );
        wp_enqueue_script(
            $this->plugin_name,
            plugin_dir_url( __FILE__ ) . 'js/mysterx-public.js',
            array('jquery'),
            $this->version,
            false
        );
        wp_localize_script( $this->plugin_name, 'MYSTERX', array(
            'ajax_url'   => admin_url( 'admin-ajax.php' ),
            'nonce'      => wp_create_nonce( 'mysterx_nonce' ),
            'assets_url' => MYSTERX_URL . '/public/assets/',
            'claim_page' => get_permalink( $options['claim_page_id'] ?? 0 ),
        ) );
    }

    /**
     * Templating with plugin folder
     *
     * @param  string $template template.
     * @param  string $template_name template_name.
     * @param  string $template_path template_path.
     * @return string
     */
    public function woocommerce_locate_template( $template, $template_name, $template_path ) {
        $default = $template;
        if ( !$template_path ) {
            $template_path = WC()->template_url;
        }
        // Look within passed path within the theme - this is priority.
        $located = locate_template( array(trailingslashit( $template_path ) . $template_name, $template_name) );
        $plugin_path = plugin_dir_path( __DIR__ ) . 'templates/';
        if ( !$located && file_exists( $plugin_path . $template_name ) ) {
            $located = $plugin_path . $template_name;
        }
        return ( $located ? $located : $default );
    }

    /**
     * Add my account tab
     *
     * @param  array $items - all tabs items.
     * @return array $items
     */
    public static function add_my_account_tab( $items ) {
        $spending_limits = array(
            'mysterx' => esc_html__( 'Boxes', 'mysterx-mystery-boxes-for-woocommerce' ),
        );
        $after_key = 'payment-methods';
        $index = array_search( $after_key, array_keys( $items ), true );
        $items = array_slice( $items, 0, $index + 1 ) + $spending_limits + $items;
        return $items;
    }

    /**
     * Register the endpoint for the spending_limits tab
     *
     * @return void
     */
    public static function add_my_account_endpoint() {
        add_rewrite_endpoint( 'mysterx', EP_ROOT | EP_PAGES );
        add_rewrite_endpoint( 'mysterx-wins', EP_ROOT | EP_PAGES );
    }

    /**
     * Add new query var.
     *
     * @param array $vars existing vars.
     * @return array
     */
    public function add_query_vars( $vars ) {
        $vars['mysterx'] = 'mysterx';
        $vars['mysterx-wins'] = 'mysterx-wins';
        return $vars;
    }

    /**
     * Get template for endpoint
     *
     * @param  mixed $current_page current_page.
     **/
    public static function my_account_mysterx_content( $current_page ) {
        global $wpdb;
        $current_user_id = get_current_user_id();
        $current_page = ( empty( $current_page ) ? 1 : absint( $current_page ) );
        $default_posts_per_page = apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() );
        $customer_instant_wins = array();
        $max_num_pages = '';
        $ofset = ($current_page - 1) * $default_posts_per_page;
        $countresults = $wpdb->get_var( $wpdb->prepare(
            'SELECT COUNT(1)
		        FROM %i as l
				LEFT JOIN %i as o ON l.id = o.id
				WHERE l.user_id = %d
				  AND o.opened_at IS NULL',
            MYSTERX_TBL_LOG,
            MYSTERX_TBL_OPEN_LOG,
            $current_user_id
        ) );
        $max_num_pages = ceil( intval( $countresults ) / intval( $default_posts_per_page ) );
        $results = $wpdb->get_results( $wpdb->prepare(
            'SELECT
				l.product_id,
				l.order_id,
				o.opened_at
				FROM %i as l
				LEFT JOIN %i as o ON l.id = o.id
				WHERE l.user_id = %d
				  AND o.opened_at IS NULL
				ORDER BY `date` ASC
				LIMIT %d OFFSET %d',
            MYSTERX_TBL_LOG,
            MYSTERX_TBL_OPEN_LOG,
            $current_user_id,
            $default_posts_per_page,
            $ofset
        ), ARRAY_A );
        wc_get_template( 'myaccount/mysterx.php', array(
            'current_page'    => absint( $current_page ),
            'boxes'           => $results,
            'max_num_pages'   => intval( $max_num_pages ),
            'wp_button_class' => ( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ),
        ) );
    }

    /**
     * Get template for endpoint
     *
     * @param  mixed $current_page current_page.
     **/
    public static function my_account_mysterx_win_content( $current_page ) {
        global $wpdb;
        $current_user_id = get_current_user_id();
        $current_page = ( empty( $current_page ) ? 1 : absint( $current_page ) );
        $default_posts_per_page = apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() );
        $customer_instant_wins = array();
        $max_num_pages = '';
        $ofset = ($current_page - 1) * $default_posts_per_page;
        $countresults = $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(1)
		        FROM %i as o
				WHERE o.user_id = %d
				AND o.opened_at IS NOT NULL', MYSTERX_TBL_OPEN_LOG, $current_user_id ) );
        $max_num_pages = ceil( intval( $countresults ) / intval( $default_posts_per_page ) );
        $results = $wpdb->get_results( $wpdb->prepare(
            'SELECT
				o.reward_id,
				o.opened_at
				FROM %i as o
				WHERE o.user_id = %d
				AND o.opened_at IS NOT NULL
				ORDER BY o.opened_at DESC
				LIMIT %d OFFSET %d',
            MYSTERX_TBL_OPEN_LOG,
            $current_user_id,
            $default_posts_per_page,
            $ofset
        ), ARRAY_A );
        wc_get_template( 'myaccount/mysterx-wins.php', array(
            'current_page'    => absint( $current_page ),
            'boxes'           => $results,
            'max_num_pages'   => intval( $max_num_pages ),
            'wp_button_class' => ( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ),
        ) );
    }

    /**
     * Modify add to cart button in loop
     *
     * @param  mixed $data data.
     * @param  mixed $product product.
     * @return mixed
     */
    public function woocommerce_loop_add_to_cart_args( $data, $product ) {
        global $myster_opening;
        if ( true === $myster_opening ) {
            $data['class'] = $data['class'] . ' open-box-button';
        }
        return $data;
    }

    /**
     * Modify add to cart url
     *
     * @param  mixed $url url.
     * @param  mixed $product product.
     * @return mixed
     */
    public function woocommerce_product_add_to_cart_url( $url, $product ) {
        global $myster_win;
        if ( true === $myster_win ) {
            return $product->get_permalink();
        }
        return $url;
    }

    /**
     * Modify is purchasable
     *
     * @param  mixed $data data.
     * @param  mixed $product product.
     * @return mixed
     */
    public function woocommerce_is_purchasable( $data, $product ) {
        global $myster_win;
        if ( true === $myster_win ) {
            return false;
        }
        return $data;
    }

    /**
     * Modify add to cart link in loop
     *
     * @param  mixed $data data.
     * @param  mixed $product product.
     * @return mixed
     */
    public function woocommerce_loop_add_to_cart_link( $data, $product ) {
        global $myster_win, $myster_opening;
        if ( true === $myster_win ) {
            return false;
        }
        if ( true === $myster_opening && $product->get_type() === 'mysterx' && $product->is_there_reward() === false ) {
            return false;
        }
        return $data;
    }

    /**
     * Modify product link in loop
     *
     * @param  mixed $url url.
     * @param  mixed $product product.
     * @return mixed
     */
    public function woocommerce_loop_product_link( $url, $product ) {
        global $myster_win;
        if ( true === $myster_win ) {
            return get_permalink( $product->get_id() );
        }
        return $url;
    }

    /**
     * Ajax open box
     *
     * @return void
     */
    public function wc_open_box_ajax() {
        check_ajax_referer( 'mysterx_nonce', 'nonce' );
        $user_id = get_current_user_id();
        $product_id = absint( $_POST['product_id'] ?? 0 );
        if ( !$product_id ) {
            wp_send_json_error( array(
                'message' => esc_html__( 'No product id.', 'mysterx-mystery-boxes-for-woocommerce' ),
            ) );
        }
        if ( !mysterx_check_if_user_can_open_box( $user_id, $product_id ) ) {
            wp_send_json_error( array(
                'message' => esc_html__( 'User can not open this box', 'mysterx-mystery-boxes-for-woocommerce' ),
            ) );
        }
        $items = mysterx_get_items_for_product( $product_id );
        if ( empty( $items ) ) {
            wp_send_json_error( array(
                'message' => esc_html__( 'No items configured.', 'mysterx-mystery-boxes-for-woocommerce' ),
            ) );
        }
        $product = wc_get_product( intval( $product_id ) );
        if ( !$product ) {
            wp_send_json_error( array(
                'message' => esc_html__( 'Invalid product.', 'mysterx-mystery-boxes-for-woocommerce' ),
            ) );
        }
        $counts_raw = $product->get_count_of_opened_rewards();
        foreach ( $items as $it ) {
            $rid = $it['reward_id'];
            $max_qty = intval( $it['qty'] );
            $already_opened = ( isset( $counts_raw[$rid] ) ? intval( $counts_raw[$rid]->total_used ) : 0 );
            if ( $already_opened < $max_qty ) {
                $available_items[] = $it;
            }
        }
        if ( empty( $available_items ) ) {
            wp_send_json_error( array(
                'message' => esc_html__( 'All rewards have already been distributed!', 'mysterx-mystery-boxes-for-woocommerce' ),
            ) );
        }
        do_action(
            'mysterx_before_open_box',
            $user_id,
            $product_id,
            $available_items
        );
        $selected = $available_items[array_rand( $available_items )];
        $selected['weight'] = 0;
        if ( !$selected ) {
            wp_send_json_error( array(
                'message' => esc_html__( 'Pick failed', 'mysterx-mystery-boxes-for-woocommerce' ),
            ) );
        }
        $selected = apply_filters(
            'mysterx_after_pick_reward',
            $selected,
            $user_id,
            $product_id
        );
        $order_id = self::create_free_woocommerce_order( $user_id, $selected['reward_id'] );
        mysterx_log_open(
            $user_id,
            $product_id,
            $order_id,
            $selected['reward_id']
        );
        $p = wc_get_product( intval( $selected['reward_id'] ) );
        $img_id = $p->get_image_id();
        $boxses_left_to_open = $product->get_number_of_boxses_for_openning_for_user( $user_id );
        do_action(
            'mysterx_after_open_box',
            $user_id,
            $product_id,
            $selected,
            $order_id
        );
        if ( $boxses_left_to_open > 0 ) {
            $message = sprintf( 
                /* translators: %d: number of boxes left to open */
                _n(
                    'You have %d box left to open',
                    'You have %d boxes left to open',
                    $boxses_left_to_open,
                    'mysterx-mystery-boxes-for-woocommerce'
                ),
                $boxses_left_to_open
             );
        } else {
            $message = esc_html__( 'You have opened all your boxes!', 'mysterx-mystery-boxes-for-woocommerce' );
        }
        $json = array(
            'item'                  => array(
                'reward_id' => $selected['reward_id'],
                'title'     => $p->get_name(),
                'image'     => ( $img_id ? wp_get_attachment_image_url( $img_id, 'thumbnail' ) : wc_placeholder_img_src() ),
                'weight'    => $selected['weight'],
                'rarity'    => mysterx_get_rarity_class_by_weight( $selected['weight'], $product_id, $selected['reward_id'] ),
            ),
            'box_left_to_open'      => $boxses_left_to_open,
            'box_left_to_open_text' => $message,
        );
        $json = apply_filters(
            'mysterx_open_box_ajax_json',
            $json,
            $user_id,
            $product_id,
            $selected
        );
        wp_send_json_success( $json );
    }

    /**
     * Create free woocommerce order
     *
     * @param  mixed $user_id user_id.
     * @param  mixed $product_id product_id.
     * @return mixed
     */
    public function create_free_woocommerce_order( $user_id, $product_id ) {
        $user = get_user_by( 'ID', $user_id );
        if ( !$user ) {
            return new WP_Error('invalid_user', esc_html__( "User don't exist", 'mysterx-mystery-boxes-for-woocommerce' ));
        }
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            return new WP_Error('invalid_product', esc_html__( "Product don't exist", 'mysterx-mystery-boxes-for-woocommerce' ));
        }
        try {
            $order = wc_create_order( array(
                'customer_id' => $user_id,
                'status'      => 'pending',
            ) );
            $order->add_product( $product, 1, array(
                'subtotal' => 0,
                'total'    => 0,
            ) );
            $order->set_total( 0 );
            $order->add_order_note( esc_html__( 'Reward from opening box!', 'mysterx-mystery-boxes-for-woocommerce' ) );
            $order->save();
            $order->update_status( 'reward', 'Reward from opening box!', true );
            return $order->get_id();
        } catch ( Exception $e ) {
            return new WP_Error('order_creation_failed', $e->getMessage());
        }
    }

    /**
     * Add open box button to order details and emails
     *
     * @param WC_Order $order Order object.
     * @param bool     $sent_to_admin Whether the email is sent to admin.
     * @param bool     $plain_text Whether the email is plain text.
     * @param string   $email Email identifier.
     * @return void
     */
    public function add_open_box_button_to_order(
        $order,
        $sent_to_admin = false,
        $plain_text = false,
        $email = ''
    ) {
        if ( $sent_to_admin || $plain_text ) {
            return;
        }
        if ( !is_a( $order, 'WC_Order' ) ) {
            return;
        }
        $has_mysterx = false;
        foreach ( $order->get_items() as $item ) {
            $product = $item->get_product();
            if ( $product && $product->get_type() === 'mysterx' ) {
                $has_mysterx = true;
                break;
            }
        }
        if ( !$has_mysterx ) {
            return;
        }
        global $wpdb;
        $order_id = $order->get_id();
        $unopened_count = $wpdb->get_var( $wpdb->prepare(
            'SELECT COUNT(1)
				FROM %i as l
				LEFT JOIN %i as o ON l.id = o.id
				WHERE l.order_id = %d
				  AND o.opened_at IS NULL',
            MYSTERX_TBL_LOG,
            MYSTERX_TBL_OPEN_LOG,
            $order_id
        ) );
        wc_get_template( 'order/mysterx-open-box.php', array(
            'unopened_count' => intval( $unopened_count ),
            'url'            => wc_get_endpoint_url( 'mysterx', '', wc_get_page_permalink( 'myaccount' ) ),
            'order'          => $order,
        ) );
    }

}
