<?php
/**
 *
 * This class defines all code related to custom rest api endpoints.
 *
 * @since      1.2.13
 * @package    Wcmlim
 * @subpackage Wcmlim/includes
 * @author     techspawn1 <contact@techspawn.com>
 */
class Wcmlim_Rest_Api
{
    public function __construct(){
        add_action( "rest_api_init", [$this, "wcmlim_register_rest_routes"]);
        add_action('woocommerce_api_loaded', [$this, "wcmlim_load_apifile"]);
        add_filter('woocommerce_api_classes', [$this, "wcmlim_init_api_class"]);
        add_action("woocommerce_rest_insert_product_object", [$this,"wcmlim_set_location_oninsert"], 10, 3);
        add_filter('woocommerce_rest_prepare_product_object', [$this,'wcmlim_modify_product_object'], 10, 3);
    }

    /**
     * Registers all rest routes
     */
    public function wcmlim_register_rest_routes(){
        $routes = [
            // Locations rest route
            [
                'route' => '/locations',
                'methods' => 'GET',
                'callback' => 'wcmlim_rest_location',
            ],
            // Locations create rest route
            [
                'route' => '/locations/create/',
                'methods' => 'POST',
                'callback' => 'wcmlim_rest_create_location',
            ],
            // Update outlet location stock
            [
                'route' => '/update/stockupppos/outlet/stock/',
                'methods' => 'POST',
                'callback' => 'wcmlim_rest_update_outlet_location_stock',
            ],
            // Locations update rest route
            [
                'route' => '/locations/update/(?P<id>\d+)',
                'methods' => 'POST',
                'callback' => 'wcmlim_rest_update_location',
            ],
            // Locations delete rest route
            [
                'route' => '/locations/remove/(?P<id>\d+)',
                'methods' => 'GET',
                'callback' => 'wcmlim_rest_remove_location',
            ],
            // Locations read rest route
            [
                'route' => '/locations/read/(?P<id>\d+)',
                'methods' => 'GET',
                'callback' => 'wcmlim_rest_read_location',
            ],
            // Get mapping location outlet route
            [
                'route' => '/get/mappinglocation/outlet/(?P<id>\d+)',
                'methods' => 'GET',
                'callback' => 'wcmlim_rest_read_outlet_location_id',
            ],
        ];

        foreach ($routes as $route) {
            register_rest_route('wc/v3', $route['route'], array(
                'methods' => $route['methods'],
                'callback' => [$this, $route['callback']],
                'permission_callback' => array($this, 'wcmlim_rest_permission_callback'),
            ));
        }
    }

    /**
     * Added WooCommerce's REST API authentication for custom endpoints
     * @since 4.0.5
     */
    public function wcmlim_rest_permission_callback($request) {
        return current_user_can('edit_posts'); 
    }
    
    /**
     * callback function for locations rest route
     */
    public function wcmlim_rest_location()
    {
        $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
        if (empty($terms)) {
            return new WP_Error('empty_locations', 'there is no Locations', array('status' => 404));
        }
        return $terms;
    }

    //remove location rest api endpoint callback
    function wcmlim_rest_remove_location(WP_REST_Request $request)
    {
        $term_id = isset($request['id']) ? intval($request['id']) : 0;
        if($term_id > 0){
            $result = wp_delete_term($term_id, "locations");
            if (is_wp_error($result)) {
                return new WP_Error('delete_failed', $result->get_error_message(), array('status' => 400));
            }
            return ["message" => "Removed Requested Location", "status" => 200];
        } else {
            return new WP_Error('not_found', "Requested Location #{$term_id} not found", array('status' => 404));
        }
    }

    //read location rest api endpoint callback
    function wcmlim_rest_read_location(WP_REST_Request $request)
    {
        $term_id = isset($request['id']) ? intval($request['id']) : 0;
        if ($term_id <= 0) {
            return new WP_Error('invalid_id', "Invalid location ID provided", array('status' => 400));
        }
        
        $term = get_term($term_id, 'locations');
        if (!$term || is_wp_error($term)) {
            return new WP_Error('not_found', "Requested Location #{$term_id} not found", array('status' => 404));
        }
        
        return $term;
    }

    /**
     * Helper function to update product stock at a specific location
     * @param int $product_id Product ID
     * @param int $location_id Location term ID
     * @param int $qty Quantity to reduce
     * @param WC_Order $order Order object
     * @return array Updated stock information
     */
    private function update_product_location_stock($product_id, $location_id, $qty, $order) {
        $product = wc_get_product($product_id);
        if (!$product) {
            return false;
        }
        
        $term_name = get_term($location_id)->name;
        $product_current_qty = get_post_meta($product_id, "wcmlim_stock_at_{$location_id}", true);
        $postmeta_backorders = get_post_meta($product_id, '_backorders', true);
        $allow_backorders = ($postmeta_backorders == "yes" || $postmeta_backorders == "notify");
        
        // Calculate new stock level
        if ($allow_backorders || $qty <= $product_current_qty) {
            $product_updated_qty = intval($product_current_qty) - intval($qty);
        } else {
            $product_updated_qty = 0;
        }
        
        // Update location stock
        update_post_meta($product_id, "wcmlim_stock_at_{$location_id}", $product_updated_qty);
        
        // Update total stock
        $this->recalculate_product_stock($product_id);
        
        // Add order note
        $note = "{ Stock levels reduced: {$product->get_formatted_name()} from Location: {$term_name} {$product_current_qty} &rarr; {$product_updated_qty} }";
        $order->add_order_note($note);
        
        return [
            'product_id' => $product_id,
            'location_id' => $location_id,
            'previous_qty' => $product_current_qty,
            'updated_qty' => $product_updated_qty
        ];
    }
    
    /**
     * Recalculates product total stock from all locations
     * @param int $product_id Product ID
     * @return int Total stock quantity
     */
    private function recalculate_product_stock($product_id) {
        $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
        $total_stock = 0;
        
        foreach ($terms as $term) {
            $loc_stock = intval(get_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", true));
            $total_stock += $loc_stock;
        }
        
        update_post_meta($product_id, "_stock", $total_stock);
        wp_update_post($product_id);
        
        return $total_stock;
    }

    /**
     * Helper function to update multiple term meta values
     * @param int $term_id Term ID
     * @param array $meta_data Array of meta keys and values
     */
    private function update_location_meta($term_id, $meta_data) {
        foreach ($meta_data as $key => $value) {
            if (!empty($value)) {
                update_term_meta($term_id, $key, sanitize_text_field($value));
            }
        }
    }
    
    /**
     * Get stockupp pos outlets location id rest api endpoint callback
     */
    function wcmlim_rest_update_outlet_location_stock(WP_REST_Request $request) {
        $response = array();
        $parameter = $request->get_params();
        
        if(empty($parameter)) {
            return new WP_Error('missing_params', 'Required parameters missing', array('status' => 400));
        }

        if(isset($parameter[0])) {
            $parameter = $parameter[0];
        }
        
        $order_id = isset($parameter['order_id']) ? $parameter['order_id'] : "";
        $location_id = isset($parameter['location_id']) ? $parameter['location_id'] : "";
        
        $order = wc_get_order($order_id);
        if (!$order) {
            return new WP_Error('invalid_order', 'Invalid order ID provided', array('status' => 400));
        }

        $updated_items = [];
        
        foreach ($order->get_items() as $item) {
            if (!$item->is_type('line_item')) {
                continue;
            }
            
            $product = $item->get_product();
            $product_id = $product->get_id();
            $qty = apply_filters('woocommerce_order_item_quantity', $item->get_quantity(), $order, $item);
            
            // Mark stock as reduced for this item
            $item->add_meta_data('_reduced_stock', $qty, true);
            $item->save();
            
            // Update stock at specified location
            $result = $this->update_product_location_stock($product_id, $location_id, $qty, $order);
            if ($result) {
                $updated_items[] = $result;
            }
        }
        
        return [
            "message" => "Order stock updated",
            "order_id" => $order_id,
            "location_id" => $location_id,
            "updated_items" => $updated_items
        ];
    }

    /**
     * Get location ID by StockUpp POS outlet ID
     */
    function wcmlim_rest_read_outlet_location_id(WP_REST_Request $request) {
        $pos_outlet_term_id = isset($request['id']) ? intval($request['id']) : 0;
        if ($pos_outlet_term_id <= 0) {
            return new WP_Error('invalid_id', "Invalid outlet ID provided", array('status' => 400));
        }
        
        $matching_terms = [];
        $terms = get_terms(array(
            'taxonomy' => 'locations', 
            'hide_empty' => false, 
            'parent' => 0,
            'meta_query' => [
                [
                    'key' => 'wcmlim_stockupp_pos',
                    'value' => $pos_outlet_term_id,
                    'compare' => '='
                ]
            ]
        ));
        
        if (!empty($terms) && !is_wp_error($terms)) {
            $matching_terms[] = $terms[0]->term_id;
            return $matching_terms;
        }
        
        return new WP_Error('not_found', "Requested Outlet #{$pos_outlet_term_id} mapping not found", array('status' => 404));
    }

    /**
     * Update location rest api endpoint callback
     */
    function wcmlim_rest_update_location(WP_REST_Request $request) {
        $term_id = intval($request['id']);
        $parameter = $request->get_params();
        
        // Check if term exists
        $term_data = get_term_by('id', $term_id, 'locations');
        if (!$term_data) {
            return new WP_Error('not_found', "Location #{$term_id} not found", array('status' => 404));
        }

        // Update term name and slug if provided
        $term_args = [];
        if (!empty($parameter['name'])) {
            $term_args['name'] = sanitize_text_field($parameter['name']);
        }
        if (!empty($parameter['slug'])) {
            $term_args['slug'] = sanitize_text_field($parameter['slug']);
        }
        
        if (!empty($term_args)) {
            wp_update_term($term_id, 'locations', $term_args);
            // Refresh term data after update
            $term_data = get_term_by('id', $term_id, 'locations');
        }

        // Prepare meta data to update
        $meta_fields = [
            'wcmlim_street_number', 'wcmlim_route', 'wcmlim_locality',
            'wcmlim_administrative_area_level_1', 'wcmlim_postal_code',
            'wcmlim_country', 'wcmlim_email', 'wcmlim_phone',
            'wcmlim_start_time', 'wcmlim_end_time'
        ];
        
        $meta_data = [];
        foreach ($meta_fields as $field) {
            if (isset($parameter[$field])) {
                $meta_data[$field] = $parameter[$field];
            }
        }
        
        // Update term meta
        $this->update_location_meta($term_id, $meta_data);
        
        // Prepare response
        $response = [
            "term_id" => $term_id,
            "term_name" => $term_data->name,
            "term_slug" => $term_data->slug
        ];
        
        // Add meta values to response
        foreach ($meta_fields as $field) {
            $response[$field] = get_term_meta($term_id, $field, true);
        }
        
        return $response;
    }

    /**
     * Create location rest api endpoint callback
     */
    function wcmlim_rest_create_location(WP_REST_Request $request) {
        $parameter = $request->get_params();
        if(empty($parameter)){
            return new WP_Error('missing_params', 'Required parameters missing', array('status' => 400));
        }
       
        $loc_name = isset($parameter['name']) ? sanitize_text_field($parameter['name']) : "";
        $loc_slug = isset($parameter['slug']) ? sanitize_text_field($parameter['slug']) : "";
        
        if (empty($loc_name)) {
            return new WP_Error('empty_name', 'Location name is required', array('status' => 400));
        }
    
        // Check if location exists
        $validate_loc = get_term_by('name', $loc_name, "locations");
        
        if ($validate_loc === false) {
            $term = wp_insert_term($loc_name, "locations", ['slug' => $loc_slug]);
            if (is_wp_error($term)) {
                return new WP_Error('creation_failed', $term->get_error_message(), array('status' => 400));
            }
            $term_id = $term['term_id'];
        } else {
            $term_id = $validate_loc->term_id;
        }
        
        // Prepare meta data
        $meta_fields = [
            'wcmlim_street_number', 'wcmlim_route', 'wcmlim_locality',
            'wcmlim_administrative_area_level_1', 'wcmlim_postal_code',
            'wcmlim_country', 'wcmlim_email', 'wcmlim_phone',
            'wcmlim_start_time', 'wcmlim_end_time'
        ];
        
        $meta_data = [];
        foreach ($meta_fields as $field) {
            if (isset($parameter[$field])) {
                $meta_data[$field] = $parameter[$field];
            }
        }
        
        // Update term meta
        $this->update_location_meta($term_id, $meta_data);
        
        // Prepare response
        $response = [
            "id" => $term_id,
            "name" => $loc_name,
            "slug" => $loc_slug
        ];
        
        // Add meta values to response
        foreach ($meta_fields as $field) {
            $response[$field] = get_term_meta($term_id, $field, true);
        }
        
        // Save as option
        update_option("taxonomy_$term_id", $response, false);
        
        return $response;
    }

    public function wcmlim_load_apifile () {
        require_once plugin_dir_path(dirname(__FILE__)) . 'includes/wcmlim-api.php';
    }

    public function wcmlim_init_api_class($classes) {
        $classes[] = 'WC_API_WCMLIM';
        return $classes;
    }

    /**
     * This callback function modify existing product object
     * and added locations data key with locations ids as a value
     * @since 1.2.13
     */
    public function wcmlim_modify_product_object($response, $object, $request) {
        if (empty($response->data))
            return $response;
        $id = $object->get_id(); //it will fetch product id 
        $response->data['locations_data'] = wp_get_object_terms( $id, 'locations', array( 'fields' => 'ids' ) );
        return $response;
    }

    /**
     * This callback function responsible for add product to 
     * custom taxonomy locations
     * @since 1.2.13
     */
    public function wcmlim_set_location_oninsert( $product, $request, $true ) {
        $params = $request->get_json_params();
        $ID = $product->get_id();
        if(is_array($params) && array_key_exists("locations_data", $params)) {
            wp_set_object_terms( $ID, $params["locations_data"], 'locations' );
        }
    }
}

new Wcmlim_Rest_Api();