<?php

use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;

/**
 * The class for managing tracking numbers on the admin side
 *
 * @since   1.8.8 - Added HPOS Compatibility
 * @since   1.8.7 - Added
 * @version 1.8.7
 * @package WCVendors_Pro
 */
class WCVendors_Pro_Admin_Order_Tracking_Controller {
    /**
     * The main plugin name
     *
     * @var string
     * @version 1.8.7
     * @since   1.8.7
     */
    public $plugin_name;
    /**
     * The current plugin version
     *
     * @var string
     * @version 1.8.7
     * @since   1.8.7
     */
    public $version;
    /**
     * Whether debug is enabled or not.
     *
     * @var boolean
     * @version 1.8.7
     * @since   1.8.7
     */
    public $debug;
    /**
     * The plugin's base directory
     *
     * @var string
     * @version 1.8.7
     * @since   1.8.7
     */
    public $base_dir;
    /**
     * The plugin's base url
     *
     * @var string
     * @version 1.8.7
     * @since   1.8.7
     */
    public $base_url;
    /**
     * The suffix for the plugin
     *
     * @var string
     * @version 1.8.7
     * @since   1.8.7
     */
    public $suffix;

    /**
     * Delivery class
     *
     * @var WCVendors_Pro_Delivery
     * @version 1.8.7
     * @since   1.8.7
     */
    public $delivery;

    /**
     * The orders controller
     *
     * @var WCVendors_Pro_Order_Controller
     * @version 1.8.7
     * @since   1.8.7
     */
    public $orders;

    /**
     * Constructor for this class
     *
     * @param string  $plugin_name The main plugin object.
     * @param string  $version The current plugin version.
     * @param boolean $debug Whether debug is enabled or not.
     * @version 1.8.7
     * @since   1.8.7
     */
    public function __construct( $plugin_name, $version, $debug ) {
        $this->plugin_name = $plugin_name;
        $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';

        $this->delivery = WCVendors_Pro_Delivery::get_instance();
        $this->orders   = WCVendors_Pro_Order_Controller::get_instance( $plugin_name, $version, $debug );
    }

    /**
     * Add order tracking meta boxes
     *
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     * @since   1.8.8 - Added HPOS Compatibility
     */
    public function add_meta_boxes() {
        $screen = wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled()
            ? wc_get_page_screen_id( 'shop-order' )
            : 'shop_order';

        add_meta_box(
            'wcvendors_order_tracking_fields_meta_box',
            __( 'Add Tracking Number', 'wcvendors-pro' ),
            array(
                $this,
                'render_tracking_fields',
            ),
            $screen,
            'side',
            'default',
        );

        add_meta_box(
            'wcvendors_order_tracking_info_meta_box',
            __( 'Order Tracking Information', 'wcvendors-pro' ),
            array(
                $this,
                'render_order_tracking_information',
            ),
            $screen,
            'normal',
            'default',
        );
    }

    /**
     * Add shipping tracking meta box
     *
     * @param WP_Post|WC_Order $post The current post object.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function render_tracking_fields( $post ) {
        $order_id = is_a( $post, 'WP_Post' ) ? $post->ID : $post->get_id();

        $order = wc_get_order( $order_id );

        $vendors   = $this->delivery->get_all_vendors_from_order( $order );
        $vendors[] = 1; // Add admin to the list of vendors.

        $args = array(
            'custom_attributes' => array(),
        );

        WCVendors_Pro_Tracking_Number_Form::shipping_provider( '', $order_id );

        WCVendors_Pro_Tracking_Number_Form::tracking_number( '', $order_id, $args );

        WCVendors_Pro_Tracking_Number_Form::date_shipped( '', $order_id, $args );

        $vendor_args = array(
            'who'         => '',
            'role__in'    => array( 'vendor', 'administrator' ),
            // translators: %s: Name used to refer to a vendor.
            'placeholder' => sprintf( __( 'Select a %s', 'wcvendors-pro' ), wcv_get_vendor_name() ),
            'id'          => 'wcv_tracking_vendor_id',
            'class'       => 'form-field',
            'authors'     => $vendors,
        );

        ?>
        <div id="wcv_tracking_number_container" class="control-group">
            <label for="wcv_tracking_vendor_id"><?php echo esc_attr( wcv_get_vendor_name() ); ?></label>
            <div class="control">
                <?php
                echo wp_kses(
                    wcv_vendor_selectbox( $vendor_args, false, false ),
                    $this->allowed_html()
                );
                ?>
            </div>
        </div>
        <?php

        wp_nonce_field( 'wcv_add_tracking', 'wcv_add_tracking_nonce' );

        WCVendors_Pro_Tracking_Number_Form::form_data(
            $order_id,
            __( 'Add tracking number', 'wcvendors-pro' ),
            array(
                'class' => 'button button-primary wcv_tracking_submit',
            )
        );
    }

    /**
     * Render order tracking information
     *
     * @param WP_Post $post The post object being edited.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function render_order_tracking_information( $post ) {
        $tracking_data = $this->format_tracking_information( $post );

        if ( empty( $tracking_data ) ) {
            echo wp_kses_post(
                sprintf(
                    '<p>%s</p>',
                    __( 'No tracking information available.', 'wcvendors-pro' )
                )
            );
            return;
        }

        $view_file = apply_filters(
            'wcvendors_pro_tracking_information_view_file',
            'views/order/tracking-information.php'
        );

        include_once $view_file;
    }

    /**
     * Save the tracking meta box data
     *
     * @param int $post_id The post ID.
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function save_tracking_number_meta_box( $post_id ) {
        $no_nonce = isset( $_POST['nonce'] ) || empty( $_POST['nonce'] );

        if ( $no_nonce || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'wcv_add_tracking' ) ) {
            return;
        }

        $this->format_posted_data();
        $this->orders->update_shipment_tracking();
    }

    /**
     * Process ajax request to add tracking information.
     *
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function add_order_vendor_tracking() {
        $no_nonce = ! isset( $_POST['wcv_add_tracking_number_nonce'] ) || empty( $_POST['wcv_add_tracking_number_nonce'] );
        if ( $no_nonce || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wcv_add_tracking_number_nonce'] ) ), 'wcv_add_tracking_number' ) ) {
            wp_send_json_error(
                array(
                    'result'  => false,
                    'message' => __( 'Security verification failed.', 'wcvendors-pro' ),
                    'code'    => 'not_authorized',
                    'data'    => array(),
                    'nonce'   => wp_create_nonce( 'wcv_add_tracking_number' ),
                )
            );
            exit;
        }

        $order_id = isset( $_POST['_wcv_order_id'] ) ? absint( $_POST['_wcv_order_id'] ) : 0;

        if ( ! $order_id ) {
            wp_send_json_error(
                array(
                    'result'  => false,
                    'message' => __( 'No order ID provided.', 'wcvendors-pro' ),
                    'code'    => 'no_order_id',
                    'data'    => array(),
                    'nonce'   => wp_create_nonce( 'wcv_add_tracking_number' ),
                )
            );
            exit;
        }

        $this->format_posted_data();
        $this->orders->update_shipment_tracking();

        // Return a success response.
        wp_send_json_success(
            array(
                'result'  => true,
                'message' => __( 'Tracking information updated.', 'wcvendors-pro' ),
                'code'    => 'success',
                'data'    => array(),
                'nonce'   => wp_create_nonce( 'wcv_add_tracking_number' ),
            )
        );
        exit;
    }

    /**
     * Format posted data
     *
     * @return void
     * @version 1.8.7
     * @since   1.8.7
     */
    public function format_posted_data() {
        // phpcs:disable WordPress.Security.NonceVerification.Missing
        $order_id = isset( $_POST['_wcv_order_id'] ) ? absint( $_POST['_wcv_order_id'] ) : 0;
        if ( ! $order_id ) {
            return;
        }

        $_POST[ '_wcv_shipping_provider_' . $order_id ] = isset( $_POST['shipping_provider'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_provider'] ) ) : '';
        $_POST[ '_wcv_tracking_number_' . $order_id ]   = isset( $_POST['tracking_number'] ) ? sanitize_text_field( wp_unslash( $_POST['tracking_number'] ) ) : '';
        $_POST[ '_wcv_date_shipped_' . $order_id ]      = isset( $_POST['date_shipped'] ) ? sanitize_text_field( wp_unslash( $_POST['date_shipped'] ) ) : '';

        unset( $_POST['shipping_provider'] );
        unset( $_POST['tracking_number'] );
        unset( $_POST['date_shipped'] );

        //phpcs:enable WordPress.Security.NonceVerification.Missing
    }

    /**
     * Format the tracking information
     *
     * @param WP_Post $post The post object being edited.
     * @return array
     * @version 1.0.0
     * @since   1.0.0
     */
    public function format_tracking_information( $post ) {
        $order            = ! is_a( $post, 'WC_Order' ) ? wc_get_order( $post ) : $post;
        $tracking_details = (array) $order->get_meta( '_wcv_tracking_details', true );

        if ( empty( $tracking_details ) ) {
            return array();
        }

        $formatted_details   = array();
        $not_available_label = __( 'Not available', 'wcvendors-pro' );

        foreach ( $tracking_details as $vendor_id => $tracking ) {
            if ( empty( $tracking ) ) {
                continue;
            }
            $shipping_provider = $tracking['_wcv_shipping_provider'];
            $tracking_number   = $tracking['_wcv_tracking_number'];
            $date_shipped      = $tracking['_wcv_date_shipped'];
            $tracking_url      = $this->get_tracking_url( $tracking, $order );

            $tracking_number   = $tracking_number ? $tracking_number : $not_available_label;
            $shipping_provider = $shipping_provider ? $shipping_provider : $not_available_label;
            $date_shipped      = $date_shipped ? $date_shipped : $not_available_label;
            $tracking_url      = $tracking_url ? $tracking_url : $not_available_label;

            $formatted_details[] = array(
                'vendor_id'         => $vendor_id,
                'shop_name'         => WCV_Vendors::get_vendor_shop_name( $vendor_id ),
                'shop_url'          => WCV_Vendors::get_vendor_shop_page( $vendor_id ),
                'shipping_provider' => $shipping_provider,
                'tracking_number'   => $tracking_number,
                'date_shipped'      => $date_shipped,
                'tracking_url'      => $tracking_url,
            );
        }

        return apply_filters(
            'wcvendors_pro_admin_order_tracking_details',
            $formatted_details,
            $tracking_details,
            $order
        );
    }

    /**
     * Get the tracking URL
     *
     * @param array    $tracking The tracking information.
     * @param WC_Order $order The order object.
     * @return string
     * @version 1.8.7
     * @since   1.8.7
     */
    public function get_tracking_url( $tracking, $order ) {
        $providers = WCVendors_Pro_Order_Controller::shipping_providers();

        $shipping_postcode = $order->get_shipping_postcode();
        $country_code      = $order->get_shipping_country();

        $tracking_base_url = '';

        // Loop through providers and get the URL to input.
        foreach ( $providers as $provider_countries ) {

            foreach ( $provider_countries as $provider => $url ) {

                if ( sanitize_title( $provider ) === sanitize_title( $tracking['_wcv_shipping_provider'] ) ) {
                    $tracking_base_url = $url;
                    break;
                }
            }

            if ( $tracking_base_url ) {
                break;
            }
        }

        $tracking_url = sprintf( $tracking_base_url, $tracking['_wcv_tracking_number'], $shipping_postcode, $country_code );

        return apply_filters(
            'wcvendors_pro_admin_order_tracking_url',
            $tracking_url,
            $tracking,
            $order,
            $providers,
        );
    }

    /**
     * Get allowed html for displaying tracking fields
     *
     * @return array
     * @version 1.8.7
     * @since   1.8.7
     */
    public function allowed_html() {
        return apply_filters(
            'wcvendors_pro_admin_order_tracking_allowed_html',
            array(
                'a'      => array(
                    'href'  => array(),
                    'title' => array(),
                ),
                'label'  => array(
                    'for' => array(),
                ),
                'div'    => array(
                    'class' => array(),
                    'id'    => array(),
                    'style' => array(),
                ),
                'br'     => array(),
                'strong' => array(),
                'select' => array(
                    'class' => array(),
                    'id'    => array(),
                    'name'  => array(),
                    'value' => array(),
                    'style' => array(),
                ),
                'option' => array(
                    'value'    => array(),
                    'selected' => array(),
                ),
            )
        );
    }
}
