<?php

if (!defined('ABSPATH')) {
    exit;
}
class WC_API_Resource
{
    protected $server;
    protected $base;
    public function __construct(WC_API_Server $server)
    {
        $this->server = $server;
        add_filter('woocommerce_api_endpoints', array($this, 'register_routes'));
        foreach (array('order', 'coupon', 'customer', 'product', 'report') as $resource) {
            add_filter("woocommerce_api_{$resource}_response", array($this, 'maybe_add_meta'), 15, 2);
        }
        $response_names = array('order', 'coupon', 'customer', 'product', 'report', 'customer_orders', 'customer_downloads', 'order_note', 'order_refund', 'product_reviews', 'product_category', 'tax', 'tax_class');
        foreach ($response_names as $name) {
            add_filter("woocommerce_api_{$name}_response", array($this, 'filter_response_fields'), 20, 3);
        }
    }
    protected function validate_request($id, $type, $context)
    {
        if ('shop_order' === $type || 'shop_coupon' === $type || 'shop_webhook' === $type) {
            $resource_name = str_replace('shop_', '', $type);
        } else {
            $resource_name = $type;
        }
        $id = absint($id);
        if (empty($id)) {
            return new WP_Error("woocommerce_api_invalid_{$resource_name}_id", sprintf(__('Invalid %s ID', 'woocommerce'), $type), array('status' => 404));
        }
        if ('customer' !== $type) {
            $post = get_post($id);
            if (null === $post) {
                return new WP_Error("woocommerce_api_no_{$resource_name}_found", sprintf(__('No %1$s found with the ID equal to %2$s', 'woocommerce'), $resource_name, $id), array('status' => 404));
            }
            $post_type = 'product_variation' === $post->post_type ? 'product' : $post->post_type;
            if ($type !== $post_type) {
                return new WP_Error("woocommerce_api_invalid_{$resource_name}", sprintf(__('Invalid %s', 'woocommerce'), $resource_name), array('status' => 404));
            }
            switch ($context) {
                case 'read':
                    if (!$this->is_readable($post)) {
                        return new WP_Error("woocommerce_api_user_cannot_read_{$resource_name}", sprintf(__('You do not have permission to read this %s', 'woocommerce'), $resource_name), array('status' => 401));
                    }
                    break;
                case 'edit':
                    if (!$this->is_editable($post)) {
                        return new WP_Error("woocommerce_api_user_cannot_edit_{$resource_name}", sprintf(__('You do not have permission to edit this %s', 'woocommerce'), $resource_name), array('status' => 401));
                    }
                    break;
                case 'delete':
                    if (!$this->is_deletable($post)) {
                        return new WP_Error("woocommerce_api_user_cannot_delete_{$resource_name}", sprintf(__('You do not have permission to delete this %s', 'woocommerce'), $resource_name), array('status' => 401));
                    }
                    break;
            }
        }
        return $id;
    }
    protected function merge_query_args($base_args, $request_args)
    {
        $args = array();
        if (!empty($request_args['created_at_min']) || !empty($request_args['created_at_max']) || !empty($request_args['updated_at_min']) || !empty($request_args['updated_at_max'])) {
            $args['date_query'] = array();
            if (!empty($request_args['created_at_min'])) {
                $args['date_query'][] = array('column' => 'post_date_gmt', 'after' => $this->server->parse_datetime($request_args['created_at_min']), 'inclusive' => true);
            }
            if (!empty($request_args['created_at_max'])) {
                $args['date_query'][] = array('column' => 'post_date_gmt', 'before' => $this->server->parse_datetime($request_args['created_at_max']), 'inclusive' => true);
            }
            if (!empty($request_args['updated_at_min'])) {
                $args['date_query'][] = array('column' => 'post_modified_gmt', 'after' => $this->server->parse_datetime($request_args['updated_at_min']), 'inclusive' => true);
            }
            if (!empty($request_args['updated_at_max'])) {
                $args['date_query'][] = array('column' => 'post_modified_gmt', 'before' => $this->server->parse_datetime($request_args['updated_at_max']), 'inclusive' => true);
            }
        }
        if (!empty($request_args['q'])) {
            $args['s'] = $request_args['q'];
        }
        if (!empty($request_args['limit'])) {
            $args['posts_per_page'] = $request_args['limit'];
        }
        if (!empty($request_args['offset'])) {
            $args['offset'] = $request_args['offset'];
        }
        if (!empty($request_args['order'])) {
            $args['order'] = $request_args['order'];
        }
        if (!empty($request_args['orderby'])) {
            $args['orderby'] = $request_args['orderby'];
            if (!empty($request_args['orderby_meta_key'])) {
                $args['meta_key'] = $request_args['orderby_meta_key'];
            }
        }
        if (!empty($request_args['post_status'])) {
            $args['post_status'] = $request_args['post_status'];
            unset($request_args['post_status']);
        }
        if (!empty($request_args['in'])) {
            $args['post__in'] = explode(',', $request_args['in']);
            unset($request_args['in']);
        }
        if (!empty($request_args['not_in'])) {
            $args['post__not_in'] = explode(',', $request_args['not_in']);
            unset($request_args['not_in']);
        }
        $args['paged'] = isset($request_args['page']) ? absint($request_args['page']) : 1;
        $args = apply_filters('woocommerce_api_query_args', $args, $request_args);
        return array_merge($base_args, $args);
    }
    public function maybe_add_meta($data, $resource)
    {
        if (isset($this->server->params['GET']['filter']['meta']) && 'true' === $this->server->params['GET']['filter']['meta'] && is_object($resource)) {
            if (preg_grep('/[a-z]+_meta/', array_keys($data))) {
                return $data;
            }
            switch (get_class($resource)) {
                case 'WC_Order':
                    $meta_name = 'order_meta';
                    break;
                case 'WC_Coupon':
                    $meta_name = 'coupon_meta';
                    break;
                case 'WP_User':
                    $meta_name = 'customer_meta';
                    break;
                default:
                    $meta_name = 'product_meta';
                    break;
            }
            if (is_a($resource, 'WP_User')) {
                $meta = (array) get_user_meta($resource->ID);
            } else {
                $meta = (array) get_post_meta($resource->get_id());
            }
            foreach ($meta as $meta_key => $meta_value) {
                if (!is_protected_meta($meta_key)) {
                    $data[$meta_name][$meta_key] = maybe_unserialize($meta_value[0]);
                }
            }
        }
        return $data;
    }
    public function filter_response_fields($data, $resource, $fields)
    {
        if (!is_array($data) || empty($fields)) {
            return $data;
        }
        $fields = explode(',', $fields);
        $sub_fields = array();
        foreach ($fields as $field) {
            if (false !== strpos($field, '.')) {
                list($name, $value) = explode('.', $field);
                $sub_fields[$name] = $value;
            }
        }
        foreach ($data as $data_field => $data_value) {
            if (is_array($data_value) && in_array($data_field, array_keys($sub_fields))) {
                foreach ($data_value as $sub_field => $sub_field_value) {
                    if (!in_array($sub_field, $sub_fields)) {
                        unset($data[$data_field][$sub_field]);
                    }
                }
            } else {
                if (!in_array($data_field, $fields)) {
                    unset($data[$data_field]);
                }
            }
        }
        return $data;
    }
    protected function delete($id, $type, $force = false)
    {
        if ('shop_order' === $type || 'shop_coupon' === $type) {
            $resource_name = str_replace('shop_', '', $type);
        } else {
            $resource_name = $type;
        }
        if ('customer' === $type) {
            $result = wp_delete_user($id);
            if ($result) {
                return array('message' => __('Permanently deleted customer', 'woocommerce'));
            } else {
                return new WP_Error('woocommerce_api_cannot_delete_customer', __('The customer cannot be deleted', 'woocommerce'), array('status' => 500));
            }
        } else {
            $result = $force ? wp_delete_post($id, true) : wp_trash_post($id);
            if (!$result) {
                return new WP_Error("woocommerce_api_cannot_delete_{$resource_name}", sprintf(__('This %s cannot be deleted', 'woocommerce'), $resource_name), array('status' => 500));
            }
            if ($force) {
                return array('message' => sprintf(__('Permanently deleted %s', 'woocommerce'), $resource_name));
            } else {
                $this->server->send_status('202');
                return array('message' => sprintf(__('Deleted %s', 'woocommerce'), $resource_name));
            }
        }
    }
    protected function is_readable($post)
    {
        return $this->check_permission($post, 'read');
    }
    protected function is_editable($post)
    {
        return $this->check_permission($post, 'edit');
    }
    protected function is_deletable($post)
    {
        return $this->check_permission($post, 'delete');
    }
    private function check_permission($post, $context)
    {
        $permission = false;
        if (!is_a($post, 'WP_Post')) {
            $post = get_post($post);
        }
        if (is_null($post)) {
            return $permission;
        }
        $post_type = get_post_type_object($post->post_type);
        if ('read' === $context) {
            $permission = 'revision' !== $post->post_type && current_user_can($post_type->cap->read_private_posts, $post->ID);
        } elseif ('edit' === $context) {
            $permission = current_user_can($post_type->cap->edit_post, $post->ID);
        } elseif ('delete' === $context) {
            $permission = current_user_can($post_type->cap->delete_post, $post->ID);
        }
        return apply_filters('woocommerce_api_check_permission', $permission, $context, $post, $post_type);
    }
}