<?php

use PHP_CodeSniffer\Reports\Full;
use WC_Vendors\Classes\Front\WCV_Table_Helper;

/**
 * The WCVendors Pro Rating Class
 *
 * This class handles the Vendor ratings system
 *
 * @since      1.0.0
 * @package    WCVendors_Pro
 * @subpackage WCVendors_Pro/includes
 */
class WCVendors_Pro_Ratings_Controller {

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

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

    /**
     * Is the plugin in debug mode
     *
     * @since    1.0.0
     * @access   private
     * @var      bool $debug plugin is in debug mode
     */
    private $debug;

    /**
     * Is the plugin base directory
     *
     * @since    1.0.0
     * @access   private
     * @var      string $base_dir string path for the plugin directory
     */
    private $base_dir;

    /**
     * Is the ratings table name
     *
     * @since    1.0.0
     * @access   private
     * @var      string $table_name name of the ratings table
     */
    public static $table_name = 'wcv_feedback';

    /**
     * The plugin base URL
     *
     * @var string
     * @version 1.0.0
     * @since   1.0.0
     */
    public $base_url;

    /**
     * The minified file suffix
     *
     * @var string
     * @version 1.0.0
     * @since   1.0.0
     */
    public $suffix = '';

    /**
     * Initialize the class and set its properties.
     *
     * @since    1.0.0
     *
     * @param      string $wcvendors_pro The name of the plugin.
     * @param      string $version       The version of this plugin.
     * @param      bool   $debug         If the plugin is currently in debug mode.
     */
    public function __construct( $wcvendors_pro, $version, $debug ) {
        global $wpdb;

        $this->wcvendors_pro = $wcvendors_pro;
        $this->version       = $version;
        $this->debug         = $debug;
        $this->base_dir      = plugin_dir_path( __DIR__ );
        $this->base_url      = plugin_dir_url( __FILE__ );
        $this->suffix        = $this->debug ? '' : '.min';
    }

    /**
     * Load admin javascript
     *
     * @since    1.0.0
     */
    public function enqueue_scripts() {
    }

    /**
     * Add the styles
     *
     * @since    1.0.0
     */
    public function enqueue_styles() {

        $screen = get_current_screen();

        $screens = array(
            'woocommerce_page_wcv_pro_vendor_feedback',
            'wc-vendors_page_wcv_pro_vendor_feedback',
        );

        if ( in_array( $screen->id, $screens, true ) ) {
            // SVG Icon Styles.
            wp_enqueue_style(
                'wcv-icons',
                WCV_PRO_PUBLIC_ASSETS_URL . 'css/wcv-icons' . $this->suffix . '.css',
                array(),
                $this->version,
                'all'
            );
        }
    }

    /**
     *  Process the ratings submission
     *
     * @since   1.0.0
     * @version 1.6.0
     */
    public function process_form_submission() {

        // Is the form submitted.
        if ( ! isset( $_POST['wcv-order_id'] ) || ! isset( $_POST['_wcv-submit_feedback'] ) || ! wp_verify_nonce( $_POST['_wcv-submit_feedback'], 'wcv-submit_feedback' ) ) {
            return;
        }

        global $wpdb;

        // Iterate over each line item to leave feedback
        // TO-DO : find better way to validate data before entering during each loop
        // Only allow posting once.
        $err = true;

        foreach ( $_POST['wcv-feedback'] as $feedback ) {

            if ( empty( $feedback['star-rating'] ) && '' === $feedback['rating_title'] && '' === $feedback['comments'] ) {
                continue;
            }

            if ( empty( $feedback['star-rating'] ) ) {
                wc_add_notice( __( 'Please select a star rating.', 'wcvendors-pro' ) );

                return;
            }

            $update = array_key_exists( 'feedback_id', $feedback ) ? true : false;

            $feedback_data = array(
                'rating'       => (int) $feedback['star-rating'],
                'order_id'     => (int) $_POST['wcv-order_id'],
                'vendor_id'    => (int) $feedback['vendor_id'],
                'product_id'   => (int) $feedback['product_id'],
                'customer_id'  => (int) $feedback['customer_id'],
                'comments'     => stripslashes( $feedback['comments'] ),
                'rating_title' => stripslashes( $feedback['rating_title'] ),
            );

            if ( $update ) {
                $where    = array( 'id' => $feedback['feedback_id'] );
                $res      = $this->update_feedback( $feedback_data, $where );
                $entry_id = $feedback['feedback_id'];
            } else {
                $res      = $this->add_feedback( $feedback_data );
                $entry_id = $wpdb->insert_id;
            }

            do_action_deprecated(
                'wcv_save_product_feedback',
                array( $feedback, $update, $entry_id, $res ),
                '1.7.10',
                'wcvendors_save_product_feedback'
            );
            do_action( 'wcvendors_save_product_feedback', $feedback, $update, $entry_id, $res );
        }

        if ( $err ) {
            $notice = __( 'Your feedback has been saved.', 'wcvendors-pro' );
        } else {
            $notice = __( 'There was an error posting your feedback.', 'wcvendors-pro' );
        }

        wc_add_notice( $notice, 'success' );

        $orders_endpoint = get_option(
            'woocommerce_myaccount_orders_endpoint'
        );
        wp_safe_redirect(
            apply_filters(
                'wcv_ratings_redirect',
                get_permalink( wc_get_page_id( 'myaccount' ) ) . $orders_endpoint
            )
        );

        exit;
    }

    /**
     * Add feedback customer feedback to the database.
     *
     * @param array $feedback The feedback data.
     * @param array $format The format of the data.
     * @return int|false|WP_Error
     * @version 1.8.7
     * @since   1.8.7
     */
    public function add_feedback( $feedback, $format = array() ) {
        global $wpdb;

        $default_format = array( '%d', '%d', '%d', '%d', '%s', '%s', '%s' );

        $format = ! empty( $format ) ? $format : $default_format;

        $result = $wpdb->insert(
            $wpdb->prefix . self::$table_name,
            $feedback,
            $format
        );

        do_action( 'wcvendors_feedback_added', $feedback, $result );

        return $result;
    }

    /**
     * Update feedback in the database.
     *
     * @param array $feedback The new feedback data to be updated.
     * @param array $where The format of the data.
     * @return int|false|WP_Error
     * @version 1.8.7
     * @since   1.8.7
     */
    public function update_feedback( $feedback, $where = array() ) {
        global $wpdb;
        $default_format = array( '%d', '%d', '%d', '%d', '%s', '%s', '%s' );

        $format = ! empty( $format ) ? $format : $default_format;

        $result = $wpdb->update(
            $wpdb->prefix . self::$table_name,
            $feedback,
            $where,
            $format,
        );

        do_action( 'wcvendors_feedback_updated', $feedback, $where, $format, $result );

        return $result;
    }

    /**
     * Display the feedback form
     *
     * @since    1.0.0
     */
    public function feedback_form() {
        if ( ! class_exists( 'WC_Vendors' ) ) {
            return;
        }

        if ( WC()->is_rest_api_request() ) {
            return;
        }

        $myaccount_redirect_url = get_permalink( wc_get_page_id( 'myaccount' ) );

        if ( ( ! isset( $_GET['wcv_order_id'] ) || ! is_user_logged_in() ) && is_page() ) {
            $error_message = sprintf(
                '<p>%s<a href="%s">%s</a></p>',
                __( 'This page should not be accessed directly. Please return to the', 'wcvendors-pro' ),
                $myaccount_redirect_url,
                __( 'my account page', 'wcvendors-pro' ),
                __( 'and select an order to leave feedback.', 'wcvendors-pro' )
            );

            echo wp_kses_post(
                apply_filters(
                    'wcv_feedback_page_error_msg',
                    $error_message
                )
            );

        }

        if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( wc_clean( $_GET['_wpnonce'] ), 'wcv-leave_feedback' ) ) {
            echo wp_kses_post(
                sprintf(
                    '<p>%s <a href="%s">%s</a></p>',
                    __( 'Error verifying your security token. Please make sure you are logged in, then refresh this page and try again.', 'wcvendors-pro' ),
                    $myaccount_redirect_url,
                    __( 'Return to my account', 'wcvendors-pro' )
                )
            );
            return;
        }

        // Template variables.
        $order_id = $_GET['wcv_order_id'];
        $feedback = $this->get_order_feedback( $order_id );
        $order    = new WC_Order( $order_id );
        $products = $order->get_items();

        ob_start();
        wc_get_template(
            'feedback-form.php',
            array(
                'order_id'   => $order_id,
                'feedback'   => $feedback,
                'order'      => $order,
                'order_date' => $order->get_date_created(),
                'products'   => $products,
            ),
            'wc-vendors/front/ratings/',
            $this->base_dir . 'templates/front/ratings/'
        );

        return ob_get_clean();
    }

    /**
     * Feedback link action that hooks into the my account order page
     *
     * @since    1.0.0
     * @version  1.6.0
     *
     * @param    string $actions actions array.
     * @param    object $order   the order object.
     */
    public function feedback_link_action( $actions, $order ) {
        $feedback_status = get_option( 'wcvendors_feedback_order_status', 'processing' );
        if ( 'processing' === $feedback_status ) {
            if ( ! $order || ! $order->has_status( 'processing' ) ) {
                if ( ! $order || ! $order->has_status( 'completed' ) ) {
                    return $actions;
                }
            }
        } elseif ( ! $order || ! $order->has_status( 'completed' ) ) {
            return $actions;
        }
        $feedback_text             = $this->get_feedback_text( $order->get_id() );
        $feedback_form_page        = get_option( 'wcvendors_feedback_page_id', null );
        $nonce_url                 = wp_nonce_url(
            add_query_arg(
                'wcv_order_id',
                $order->get_id(),
                get_permalink( $feedback_form_page )
            ),
            'wcv-leave_feedback'
        );
        $actions['leave_feedback'] = array(
            'url'  => $nonce_url,
            'name' => apply_filters( 'wcv_feedback_btn_text', $feedback_text ),
        );
        return apply_filters(
            'wcv_ratings_my_account_my_orders_actions',
            $actions,
            $order,
            $feedback_text
        );
    }

    /**
     * Generate the ratings URL
     *
     * @since    1.0.0
     *
     * @param    int    $vendor_id The vendor id to generate.
     * @param    bool   $link      Otput a link, otherwise just the rating.
     * @param    string $link_text The text for the link.
     */
    public static function ratings_link( $vendor_id, $link = true, $link_text = '' ) { //phpcs:ignore

        $feedback_form_page = get_option( 'wcvendors_feedback_page_id', null );
        $feedback_system    = wc_string_to_bool( get_option( 'wcvendors_feedback_system', 'no' ) );

        $url = apply_filters(
            'wcv_ratings_link_url',
            WCVendors_Pro_Vendor_Controller::get_vendor_store_url( $vendor_id ) . 'ratings/'
        );
        ob_start();
        if ( $feedback_form_page ) {
            $ratings_count   = self::get_ratings_count( $vendor_id );
            $ratings_average = self::get_ratings_average( $vendor_id );
            include 'partials/ratings/public/wcvendors-pro-ratings-link.php';
        }
        return ob_get_clean();
    }

    /**
     * Add leave feedback button on the downloads page
     *
     * @param   array $download The download.
     * @return  void
     * @since   1.6.0
     * @version 1.6.0
     */
    public function add_feedback_link( $download ) {
        $order = wc_get_order( $download['order_id'] );
        echo wp_kses_post(
            sprintf(
                '<a href="%s" class="woocommerce-MyAccount-downloads-file button alt">%s</a>',
                esc_url( $download['download_url'] ),
                esc_html( $download['download_name'] )
            )
        );

        if ( ! empty( $order ) && is_a( $order, 'WC_Order' ) ) {
            $feedback_text      = $this->get_feedback_text( $order->get_id() );
            $feedback_form_page = get_option( 'wcvendors_feedback_page_id', null );
            $url                = wp_nonce_url( add_query_arg( 'wcv_order_id', $order->get_id(), get_permalink( $feedback_form_page ) ), 'wcv-leave_feedback' );
            $name               = apply_filters( 'wcv_feedback_btn_text', $feedback_text );
            echo wp_kses_post(
                apply_filters(
                    'wcv_download_leave_feedback_button',
                    sprintf(
                        '<a href="%s" class="woocommerce-button button leave_feedback">%s</a>',
                        $url,
                        esc_html( $feedback_text )
                    ),
                    $url,
                    $feedback_text
                )
            );
        }
    }
    /**
     * Get the text to request feedback based on the order status
     *
     * @param   int $order_id The order ID.
     * @return  string
     * @since   1.6.0
     * @version 1.6.0
     */
    public function get_feedback_text( $order_id ) {
        $existing_feedback = $this->get_order_feedback( $order_id );
        $feedback_text     = ( ! empty( $existing_feedback ) ) ? __( 'Revise Feedback', 'wcvendors-pro' ) : __( 'Leave Feedback', 'wcvendors-pro' );

        return apply_filters( 'wcv_feedback_text', $feedback_text, $order_id );
    }

    /**
     * Get the feedback for an order
     *
     * @since    1.0.0
     *
     * @param    int $order_id the order id to get.
     */
    public function get_order_feedback( $order_id ) {

        global $wpdb;

        $order_id = (int) $order_id;

        $table_name = $wpdb->prefix . self::$table_name;

        $feedback = $wpdb->get_results(
            $wpdb->prepare( 'SELECT * FROM %i WHERE order_id = %d', $table_name, $order_id )
        );

        return $feedback;
    }

    /**
     * Get the vendor feedback
     *
     * @since    1.0.0
     *
     * @param    int $vendor_id the vendor id to get feedback for.
     * @param    int $number    the number of feedback to get.
     */
    public static function get_vendor_feedback( $vendor_id, $number = - 1 ) {

        global $wpdb;

        $vendor_id  = (int) $vendor_id;
        $table_name = $wpdb->prefix . self::$table_name;
        $sort_order = get_option( 'wcvendors_feedback_sort_order', 'desc' );

        $limit = $number > 0 ? 'LIMIT ' . $number : '';

        $feedback = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM %i WHERE vendor_id = %d ORDER BY postdate $sort_order $limit", //phpcs:ignore
                $table_name,
                $vendor_id
            )
        );

        return $feedback;
    }

    /**
     * Get the product feedback
     *
     * @since    1.0.0
     *
     * @param int $product_id the vendor id to get feedback for.
     */
    public function get_product_feedback( $product_id ) {

        global $wpdb;

        $table_name = $wpdb->prefix . self::$table_name;

        $sort_order = get_option( 'wcvendors_feedback_sort_order', 'desc' );

        $feedback = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM %i WHERE product_id = %d ORDER BY postdate $sort_order", //phpcs:ignore
                $table_name,
                $product_id
            )
        );

        return $feedback;
    }

    /**
     * Get the feedback
     *
     * @since    1.0.0
     *
     * @param    int $feedback_id the feedback id.
     */
    public function get_feedback( $feedback_id ) {

        global $wpdb;

        $feedback_id = (int) $feedback_id;

        $table_name = $wpdb->prefix . self::$table_name;

        $sort_order = get_option( 'wcvendors_feedback_sort_order', 'desc' );

        $feedback = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM %i WHERE id = %d ORDER BY postdate $sort_order", //phpcs:ignore
                $table_name,
                $feedback_id,
            )
        );

        return $feedback;
    }

    /**
     * Get all feedback from table.
     *
     * @return array Array of feedback rows.
     * @version 1.8.7
     * @since   1.8.7
     */
    public function get_all_feedback() {
        global $wpdb;

        $table_name = $wpdb->prefix . self::$table_name;

        return $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i', $table_name ) );
    }

    /**
     * Get all reviews not synched
     *
     * Gets a list of reviews not associated with vendor product feedback.
     *
     * @return array
     * @version 1.8.7
     * @since   1.8.7
     */
    public function get_reviews_not_synched() {
        $meta_query = array(
            'relationship' => 'OR',
            array(
                'key'     => 'wcvendors_review_id',
                'compare' => 'NOT EXISTS',
            ),
            array(
                'key'     => 'rating_title',
                'compare' => 'NOT EXISTS',
            ),
            array(
                'key'     => 'rating',
                'compare' => 'NOT EXISTS',
            ),
        );
        return get_comments(
            array(
                'meta_query' => $meta_query,
                'post_type'  => 'review',
            )
        );
    }

    /**
     * Get the feedback
     *
     * @since    1.0.0
     *
     * @param    int $vendor_id the vendor id to get the ratings average for.
     */
    public static function get_ratings_average( $vendor_id ) {

        global $wpdb;

        $vendor_ratings = array();
        $average_rating = '';

        $vendor_id = (int) $vendor_id;

        $count = self::get_ratings_count( $vendor_id );

        $table_name = $wpdb->prefix . self::$table_name;

        $ratings = $wpdb->get_var(
            $wpdb->prepare(
                'SELECT SUM(rating) FROM %i WHERE vendor_id = %d',
                $table_name,
                $vendor_id
            )
        );

        if ( $count > 0 ) {
            $average_rating = number_format( $ratings / $count, 1 );
        } else {
            $average_rating = 0;
        }

        return $average_rating;
    }

    /**
     * Get the feedback
     *
     * @since    1.0.0
     *
     * @param    int $vendor_id the vendor id to get the ratings average for.
     */
    public static function get_ratings_count( $vendor_id ) {

        global $wpdb;

        $table_name = $wpdb->prefix . self::$table_name;

        $count = $wpdb->get_var(
            $wpdb->prepare(
                'SELECT count(rating) FROM %i WHERE vendor_id = %s',
                $table_name,
                $vendor_id
            )
        );

        return $count;
    }

    /**
     * Get the number of ratings for a product
     *
     * @param int $product_id The product ID.
     *
     * @return int number of ratings
     * @since 1.5.6
     */
    public static function get_product_ratings_count( $product_id ) {
        global $wpdb;

        $table_name = $wpdb->prefix . self::$table_name;

        $count = $wpdb->get_var(
            $wpdb->prepare(
                'SELECT count(rating) FROM %i WHERE product_id = %s',
                $table_name,
                $product_id
            )
        );

        return $count;
    }

    /**
     * Get the average rating for the product.
     *
     * @param int $product_id The product ID.
     *
     * @return int average rating for product.
     * @since 1.5.6
     */
    public static function get_product_average_rating( $product_id ) {
        global $wpdb;

        $table_name = $wpdb->prefix . self::$table_name;

        $count = self::get_product_ratings_count( $product_id );

        $sum = $wpdb->get_var(
            $wpdb->prepare(
                'SELECT SUM(rating) FROM %i WHERE product_id = %s',
                $table_name,
                $product_id
            )
        );

        if ( $sum ) {
            return $sum / $count;
        }

        return 0;
    }

    /**
     * The main admin page for the ratings
     *
     * @since    1.0.0
     */
    public function admin_page_setup() {

        $hook = add_submenu_page(
            'wc-vendors',
            __( 'Vendor Ratings', 'wcvendors-pro' ),
            __( 'Vendor Ratings', 'wcvendors-pro' ),
            'manage_woocommerce',
            'wcv_pro_vendor_feedback',
            array(
                $this,
                'ratings_admin_page',
            )
        );

        include 'class-wcvendors-pro-ratings-admin-table.php';

        add_filter( 'set-screen-option', array( $this, 'ratings_set_option' ), 10, 3 );

        add_action( "load-$hook", array( 'WCVendors_Pro_Ratings_Admin_Table', 'add_options' ) );
    }

    /**
     * Set the ratings option
     *
     * @param string $status The status of the option.
     * @param string $option The option name.
     * @param string $value The value of the option.
     *
     * @return string
     * @since 1.8.7
     */
    public function ratings_set_option( $status, $option, $value ) {
        return $value;
    }

    /**
     *  Load the admin ratings table in the wp-admin dashboard
     *
     * @since    1.0.0
     */
    public function ratings_admin_page() {

        include_once 'class-wcvendors-pro-ratings-admin-table.php';

        $ratings_table = new WCVendors_Pro_Ratings_Admin_Table( $this->wcvendors_pro, $this->version, $this->debug, self::$table_name );

        include apply_filters( 'wcvendors_pro_ratings_admin_page_table_title_path', 'partials/ratings/admin/wcvendors-pro-ratings-table-title.php' );

        // Display the edit form without the items table.
        if ( 'edit' === $ratings_table->current_action() ) {

            $id       = $_GET['wcv_vendor_rating_id']; //phpcs:ignore
            $feedback = $this->get_feedback( $id );
            $ratings_table->display_edit_form( $feedback );

        } else {

            // Process the single item actions.
            if ( isset( $_POST['action'] ) && 'save' === $_POST['action'] ) { //phpcs:ignore

                $id       = $_POST['rating_id']; //phpcs:ignore
                $comments = $_POST['rating_comments']; //phpcs:ignore
                $title    = $_POST['rating_title']; //phpcs:ignore

                $feedback = array(
                    'id'              => $id,
                    'rating_title'    => $title,
                    'rating_comments' => $comments,
                );

                $result = $ratings_table->update_rating( $feedback );

                if ( $result ) {
                    $message = sprintf(
                        /* translators: %s: vendor name */
                        __( '%s rating updated.', 'wcvendors-pro' ),
                        wcv_get_vendor_name()
                    );
                    include apply_filters(
                        'wcvendors_pro_ratings_admin_page_table_notice_path',
                        'partials/ratings/admin/wcvendors-pro-ratings-table-notice.php'
                    );
                }
            } elseif ( 'delete' === $ratings_table->current_action() ) {

                $id = $_GET['wcv_vendor_rating_id']; //phpcs:ignore

                if ( isset( $id ) ) {

                    $result = $ratings_table->delete_ratings( $id );

                    if ( $result ) {
                        $message = sprintf(
                            /* translators: %s: vendor name */
                            __( '%s rating deleted.', 'wcvendors-pro' ),
                            wcv_get_vendor_name()
                        );
                        include apply_filters(
                            'wcvendors_pro_ratings_admin_page_table_notice_path',
                            'partials/ratings/admin/wcvendors-pro-ratings-table-notice.php'
                        );
                    }
                }
            }

            include apply_filters(
                'wcvendors_pro_ratings_admin_page_table_path',
                'partials/ratings/admin/wcvendors-pro-ratings-table.php'
            );

        }

        include apply_filters(
            'wcvendors_pro_ratings_admin_page_table_end_path',
            'partials/ratings/admin/wcvendors-pro-ratings-table-end.php'
        );
    }

    /**
     *  Add the vendor ratings tab on the front end
     *
     * @param array $tabs List of tabs.
     * @since    1.0.0
     * @version  2.0.1 Added fallback to default label if the option is set but empty.
     */
    public function vendor_ratings_panel_tab( $tabs ) {

        global $post;

        $feedback_display = wc_string_to_bool( get_option( 'wcvendors_feedback_display', 'no' ) );

        if ( WCV_Vendors::is_vendor( $post->post_author ) && ! $feedback_display ) {

            $vendor_ratings_label = get_option(
                'wcvendors_vendor_ratings_label',
                __( 'Product ratings', 'wcvendors-pro' )
            );

            // Fallback to default label if the option is set but empty.
            if ( empty( $vendor_ratings_label ) ) {
                $vendor_ratings_label = __( 'Product Ratings', 'wcvendors-pro' );
            }

            $tabs['vendor_ratings_tab'] = apply_filters(
                'wcv_vendor_ratings_tab',
                array(
                    'title'    => $vendor_ratings_label,
                    'priority' => 50,
                    'callback' => array( $this, 'vendor_ratings_panel' ),
                )
            );
        }

        return $tabs;
    }

    /**
     *  Add the vendor ratings information for this product to the front end
     *
     * @since    1.0.0
     */
    public function vendor_ratings_panel() {

        global $product;

        $product_feedback = $this->get_product_feedback( $product->get_id() );
        $post             = get_post( $product->get_id() );

        echo wp_kses(
            self::ratings_link( $post->post_author, true, esc_html__( 'View All Ratings', 'wcvendors-pro' ) ),
            array(
                'a'  => array(
                    'href'  => array(),
                    'class' => array(),
                ),
                'br' => array(),
            )
        );

        if ( $product_feedback ) {

            foreach ( $product_feedback as $pf ) {

                $customer     = get_userdata( $pf->customer_id );
                $rating       = $pf->rating;
                $rating_title = $pf->rating_title;
                $comment      = $pf->comments;
                $post_date    = date_i18n( get_option( 'date_format' ), strtotime( $pf->postdate ) );
                // Handle deleted customers gracefully.
                if ( $customer && ! empty( $customer->display_name ) ) {
                    $customer_name = ucfirst( $customer->display_name );
                } else {
                    $customer_name = __( 'Unknown Customer', 'wcvendors-pro' );
                }

                wc_get_template(
                    'ratings-display-panel.php',
                    array(
                        'rating'        => $rating,
                        'rating_title'  => $rating_title,
                        'comment'       => $comment,
                        'customer_name' => $customer_name,
                        'post_date'     => $post_date,

                    ),
                    'wc-vendors/front/ratings/',
                    $this->base_dir . 'templates/front/ratings/'
                );
            }
        } else {
            echo '<div class="wcv-rating-empty">';
            echo esc_html__( 'No ratings have been submitted for this product yet.', 'wcvendors-pro' );
            echo '</div>';
        }
    }

    /**
     *  Update Table Headers for display of vendor ratings
     *
     * @since    1.0.0
     */
    public function table_columns() {

        $columns = apply_filters(
            'wcv_ratings_table_columns',
            array(
                'ID'          => array(
                    'label'         => __( 'ID', 'wcvendors-pro' ),
                    'mobile_header' => false,

                ),
                'order_id'    => array(
                    'label'         => __( 'Order', 'wcvendors-pro' ),
                    'mobile_header' => false,
                    'full_span'     => true,
                ),
                'feedback'    => array(
                    'label'         => __( 'Feedback', 'wcvendors-pro' ),
                    'mobile_header' => true,
                    'full_span'     => false,
                ),
                'rating'      => array(
                    'label'         => __( 'Rating', 'wcvendors-pro' ),
                    'mobile_header' => true,
                    'full_span'     => false,
                ),
                'product_id'  => array(
                    'label'         => __( 'Product', 'wcvendors-pro' ),
                    'mobile_header' => true,
                    'full_span'     => false,
                ),
                'customer_id' => array(
                    'label'         => __( 'Customer', 'wcvendors-pro' ),
                    'mobile_header' => true,
                    'full_span'     => false,
                ),
                'postdate'    => array(
                    'label'         => __( 'Date', 'wcvendors-pro' ),
                    'mobile_header' => true,
                    'full_span'     => false,
                ),
            )
        );

        return $columns;
    }

    /**
     *  Retrieve the vendor ratings data
     *
     * @since    1.0.0
     * @version  1.7.8
     * @return   array  $new_rows   array of stdClass objects passed back to the filter
     */
    public function table_rows() {

        $feedback = self::get_vendor_feedback( get_current_user_id() );

        $new_rows = array();
        foreach ( $feedback as $fb ) {

            $customer = get_userdata( $fb->customer_id );
            $product  = wc_get_product( $fb->product_id );

            // Handle deleted products gracefully.
            if ( ! is_a( $product, 'WC_Product' ) ) {
                $product_name = __( 'Deleted Product', 'wcvendors-pro' );
            } else {
                $product_name = $product->get_title();
            }

            // Handle deleted customers gracefully.
            if ( $customer && ! empty( $customer->display_name ) ) {
                $customer_name = ucfirst( $customer->display_name );
            } else {
                $customer_name = __( 'Unknown Customer', 'wcvendors-pro' );
            }
            $feedback = '';
            $date     = date_i18n( get_option( 'date_format' ), strtotime( $fb->postdate ) );

            $stars_witdh = 0;

            if ( ! empty( $fb->rating ) ) {
                $stars_witdh = ( $fb->rating / 5 ) * 100;
            }

            $rating_stars = '<div class="wcv-star-rating">
                <div class="wcv-star-rating-filled" style="width: ' . esc_attr( $stars_witdh ) . '%;"></div>
            </div>';

            include 'partials/ratings/admin/wcvendors-pro-ratings-feedback.php';

            $new_row             = new stdClass();
            $new_row->ID         = $fb->id;
            $new_row->order_id   = '#' . $fb->order_id;
            $new_row->feedback   = $feedback;
            $new_row->rating     = $rating_stars;
            $new_row->product_id = $product_name;
            // Handle deleted customers gracefully.
            if ( $customer && ! empty( $customer->display_name ) ) {
                $new_row->customer_id = ucfirst( $customer->display_name );
            } else {
                $new_row->customer_id = __( 'Unknown Customer', 'wcvendors-pro' );
            }
            $new_row->postdate = date_i18n( get_option( 'date_format' ), strtotime( $fb->postdate ) );

            $new_rows[] = $new_row;
        }

        return $new_rows;
    }

    /**
     *  Change the column that actions are displayed in
     *
     * @since    1.0.0
     *
     * @param  string $column column passed from filter.
     */
    public function table_action_column( $column ) { //phpcs:ignore

        $new_column = '';

        return $new_column;
    }

    /**
     *  Change the column that actions are displayed in
     *
     * @since    1.0.0
     *
     * @param   string $notice no data notice.
     *
     * @return   string $notice no data notice.
     */
    public function table_no_data_notice( $notice ) {

        $notice = __( 'No ratings found.', 'wcvendors-pro' );

        return $notice;
    }

    /**
     * Display the custom order table
     *
     * @since    1.0.0
     */
    public function display() {

        // Use the internal table generator to create object list.
        $ratings_table = new WCV_Table_Helper(
            $this->wcvendors_pro,
            $this->version,
            'rating',
            null,
            get_current_user_id()
        );

        $ratings_table->set_columns( $this->table_columns() );
        $ratings_table->set_rows( $this->table_rows() );

        // display the table.
        $ratings_table->display();
    }

    /**
     * Display the custom order table
     *
     * @since    1.2.0
     */
    public function display_vendor_ratings() {

        if ( ! is_admin() ) {

            if ( get_query_var( 'ratings' ) ) {

                $vendor_shop     = urldecode( get_query_var( 'vendor_shop' ) );
                $vendor_id       = WCV_Vendors::get_vendor_id( $vendor_shop );
                $vendor_feedback = self::get_vendor_feedback( $vendor_id );

                wc_get_template(
                    'store-ratings.php',
                    array(
                        'vendor_shop'     => $vendor_shop,
                        'vendor_id'       => $vendor_id,
                        'vendor_feedback' => $vendor_feedback,
                    ),
                    'wc-vendors/store/',
                    $this->base_dir . 'templates/store/'
                );

                exit;

            }
        }
    }

    /**
     * Add the query vars
     *
     * @param array $query_vars The query vars.
     *
     * @since    1.2.0
     */
    public function add_query_vars( $query_vars ) {

        $query_vars[] = 'ratings';

        return $query_vars;
    }

    /**
     * Add the ratings rewrite rule
     *
     * @param array $rules The rules.
     * @since    1.2.0
     */
    public function add_rewrite_rules( $rules ) {

        $permalink = untrailingslashit( get_option( 'wcvendors_vendor_shop_permalink', '' ) );

        // Remove beginning slash.
        if ( substr( $permalink, 0, 1 ) === '/' ) {
            $permalink = substr( $permalink, 1, strlen( $permalink ) );
        }

        $ratings_rule = array( $permalink . '/([^/]*)/ratings' => 'index.php?post_type=product&vendor_shop=$matches[1]&ratings=all' );
        $rules        = array_merge( $ratings_rule, $rules );

        return $rules;
    }

    /**
     * Output a vendor ratings link
     *
     * @param array $atts The shortcode attributes.
     * @since   1.5.2
     */
    public function wcv_feedback( $atts ) {

        extract( //phpcs:ignore
            shortcode_atts(
                array(
                    'vendor' => '',
                ),
                $atts
            )
        );

        ob_start();

        if ( ! wc_string_to_bool( get_option( 'wcvendors_ratings_management_cap', 'no' ) ) ) {
            echo wp_kses_post( self::ratings_link( $vendor, true ) );
        }

        return ob_get_clean();
    }


    /**
     * Output the vendors total ratings if it is a vendor page
     *
     * @param array $atts The shortcode attributes.
     *
     * @return string
     * @since 1.7.0
     */
    public function wcv_vendor_total_ratings( $atts ) { //phpcs:ignore
        global $post;
        if ( WCV_Vendors::is_vendor_page() ) {
            $vendor_shop = urldecode( get_query_var( 'vendor_shop' ) );
            $vendor_id   = WCV_Vendors::get_vendor_id( $vendor_shop );
        } elseif ( is_product() && WCV_Vendors::is_vendor_product_page( $post->post_author ) ) {
                $vendor_id = $post->post_author;
        } else {
            return;
        }

        ob_start();

        if ( ! wc_string_to_bool( get_option( 'wcvendors_ratings_management_cap', 'no' ) ) ) {
            echo wp_kses_post( self::ratings_link( $vendor_id, true ) );
        }

        return ob_get_clean();
    }

    /**
     * Synchronize WCVendors Reviews and WooCommerce Reviews
     *
     * @hooked to 'wcv_save_product_feedback'
     *
     * @param  array   $feedback a list of feedback data:
     *                    'star-rating'       => (int) the star rating (MIND THE DASH!!).
     *                    'vendor_id'         => (int) vendor_id.
     *                    'product_id'        => (int) product_id.
     *                    'customer_id'       => (int) $customer_id.
     *                    'comments'          => (string) text of the feedback.
     *                    'rating_title'      => (string) title of the feedback.
     *                    'feedback_id'       => (int) the id of the feedback if it already exists and is just being updated.
     *
     * @param  boolean $update  true if the review is being updated, false if it's a new review.
     * @param  int     $entry_id Tthe database entry ID of the inserted/updated feedback.
     * @param  mixed   $response The response we got from the database action. false if failed.
     *
     * @author  Andrea Piccart
     * @link    http://bespokewebdeveloper.com
     *
     * @since  1.8.7 Refactored the add/update routines into functions.
     * @since   1.6.0
     * @version 1.6.0
     */
    public function sync_wcv_reviews_with_woo_reviews( $feedback, $update, $entry_id, $response ) {

        if ( ! wc_string_to_bool( get_option( 'wcvendors_feedback_sync_reviews', 'no' ) ) ) {
            return;
        }

        if ( ! $response || ! $feedback || ! $feedback['customer_id'] || ! $feedback['product_id'] || ! $entry_id ) {
            return;
        }

        $comment_ID = '';
        $comments   = get_comments(
            array(
                'meta_key'   => 'wcvendors_review_id',
                'meta_value' => $entry_id,
                'user_id'    => $feedback['customer_id'],
            )
        );

        if ( $comments && is_array( $comments ) ) {

            foreach ( $comments as $comment ) {
                $comment_ID   = $comment->comment_ID;
                $comment_text = $comment->comment_content;
            }
        }

        $review_meta = array(
            'wcvendors_review_id' => $entry_id,
            'rating'              => $feedback['star-rating'],
            'review_title'        => $feedback['rating_title'],
        );

        if ( true === $update && $comment_ID ) {

            if ( $feedback['comments'] && $comment_text !== $feedback['comments'] ) {

                $updatedata = array(
                    'comment_ID'      => $comment_ID,
                    'comment_content' => stripslashes( $feedback['comments'] ),
                );

                $this->update_review( $updatedata );
            }

            $this->update_review_meta( $comment_ID, $review_meta );
        } else {

            if ( false === get_post_status( $feedback['product_id'] ) ) {
                return;
            }

            $author_data = get_user_by( 'id', $feedback['customer_id'] );

            $commentdata = array(
                'comment_post_ID'      => $feedback['product_id'],
                'comment_author'       => $author_data->display_name,
                'comment_author_email' => $author_data->user_email,
                'comment_author_url'   => $author_data->user_url,
                'comment_content'      => $feedback['comments'],
                'comment_type'         => 'review',
                'comment_parent'       => 0,
                'user_id'              => $feedback['customer_id'],
            );

            $comment_id = $this->add_review( $commentdata, $author_data );

            $this->add_review_meta( $comment_id, $review_meta );
        }
    }

    /**
     * Process scheduled action to sync reviews
     *
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function process_sync_reviews_action() {
        $feedbacks = $this->get_all_feedback();

        foreach ( $feedbacks as $feedback ) {
            $author = get_user_by( 'id', $feedback->customer_id );

            $review = array(
                'comment_post_ID' => $feedback->product_id,
                'user_id'         => $feedback->customer_id,
                'comment_content' => $feedback->comments,
                'comment_date'    => $feedback->postdate,
            );

            $review = wp_parse_args(
                $review,
                $this->get_comment_author_args( $author )
            );

            $review_meta = array(
                'wcvendors_review_id' => $feedback->id,
                'star-rating'         => $feedback->rating,
                'rating_title'        => $feedback->rating_title,
            );

            $_review_id = $this->review_exists(
                $review['user_id'],
                $review['comment_post_ID']
            );

            if ( is_int( $_review_id ) ) {
                $review['comment_ID']      = $_review_id;
                $review_meta['comment_ID'] = $_review_id;
            }

            $this->add_or_update_review( $review );
            $this->add_or_update_review_meta( $review_meta );
        }
    }

    /**
     * Add or update a review.
     *
     * @param array $review The review details.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function add_or_update_review( $review ) {
        $should_update = isset( $review['comment_ID'] ) && $review['comment_ID'] > 0 ? true : false;

        if ( $should_update ) {
            $this->update_review( $review );
            return;
        }

        $this->add_review( $review );
    }

    /**
     * Add or update review meta
     *
     * @param array $meta The review meta.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function add_or_update_review_meta( $meta ) {
        $comment_id = isset( $review['comment_ID'] ) && $meta['comment_ID'] > 0 ? $meta['comment_ID'] : 0;

        if ( ! $comment_id ) {
            $this->add_review_meta( $comment_id, $meta );
            return;
        }

        $this->update_review_meta( $comment_id, $meta );
    }

    /**
     * Add a review comment
     *
     * @param array            $review The review details.
     * @param WP_User|int|null $author The author of the review.
     * @return int|false|WP_Error Comment ID if successful, false if not updated, WP_Error if there was an error.
     * @version 1.8.7
     * @since   1.8.7
     */
    public function add_review( $review, $author = null ) {
        if ( is_null( $author ) && is_numeric( $review['user_id'] ) ) {
            $author = get_user_by( 'id', $review['user_id'] );
        }

        if ( is_numeric( $author ) ) {
            $author = get_user_by( 'id', $author );
        }

        $default_args = wp_parse_args(
            array(
                'comment_type'   => 'review',
                'comment_parent' => 0,
            ),
            $this->get_comment_author_args( $author ),
        );

        $new_review = wp_parse_args( $review, $default_args );

        return wp_new_comment( $new_review );
    }

    /**
     * Update review.
     *
     * @param array $comment Update review comment.
     * @return int|false|WP_Error
     * @version 1.8.7
     * @since   1.8.7
     */
    public function update_review( $comment ) {
        return wp_update_comment( $comment );
    }

    /**
     * Add review meta
     *
     * @param int   $comment_id The comment ID.
     * @param array $meta The meta data to add.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function add_review_meta( $comment_id, $meta ) {
        $review_id    = isset( $meta['wcvendors_review_id'] ) ? $meta['wcvendors_review_id'] : 0;
        $rating       = isset( $meta['star-rating'] ) ? $meta['star-rating'] : 0;
        $review_title = isset( $meta['rating_title'] ) ? $meta['rating_title'] : '';

        if ( $review_id ) {
            add_comment_meta( $comment_id, 'wcvendors_review_id', $comment_id );
        }
        add_comment_meta( $comment_id, 'rating', $rating );
        add_comment_meta( $comment_id, 'review_title', $review_title );
    }

    /**
     * Update review meta.
     *
     * @param int   $comment_id The comment id.
     * @param array $meta The review meta.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function update_review_meta( $comment_id, $meta ) {
        $review_id    = isset( $meta['wcvendors_review_id'] ) ? $meta['wcvendors_review_id'] : 0;
        $rating       = isset( $meta['star-rating'] ) ? $meta['star-rating'] : 0;
        $review_title = $meta['rating_title'];

        if ( $review_id && $review_id !== $comment_id ) {
            update_comment_meta( $comment_id, 'wcvendors_review_id', $review_id );
        }

        if ( $rating ) {
            update_comment_meta( $comment_id, 'rating', $rating );
        }

        if ( $meta['rating_title'] ) {
            update_comment_meta( $comment_id, 'review_title', $review_title );
        }
    }

    /**
     * Check if a review exists.
     *
     * Return the comment ID if it exists, or null otherwise.
     *
     * @param string $user_id The comment author's ID.
     * @param int    $post_id The post ID.
     * @return string|null
     * @version 1.8.7
     * @since   1.8.7
     */
    public function review_exists( $user_id, $post_id ) {
        global $wpdb;

        $result = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT comment_post_ID FROM $wpdb->comments
				WHERE user_id = %d
				AND comment_post_ID = %d",
                stripslashes( $user_id ),
                (int) $post_id
            )
        );

        return ! is_null( $result ) ? (int) $result : $result;
    }

    /**
     * Get comment author args
     *
     * @param WP_User $author The author of the comment.
     * @return array
     * @version 1.8.7
     * @since   1.8.7
     */
    public function get_comment_author_args( $author ) {
        if ( ! is_a( $author, 'WP_User' ) ) {
            return array();
        }

        return array(
            'comment_author'       => $author->display_name,
            'comment_author_email' => $author->user_email,
            'comment_author_url'   => $author->user_url,
            'user_id'              => $author->ID,
        );
    }
} // End WCVendors_Pro_Ratings
