<?php
/**
 * REST API Product Reviews controller
 *
 * Handles requests to the /products/reviews endpoint.
 *
 * @author   WooThemes
 * @category API
 * @package  WooCommerce/API
 * @since    2.6.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * REST API Products controller class.
 *
 * @package WooCommerce/API
 * @extends WC_REST_Controller
 */
class W2W_REST_Product_Reviews_Controller extends WC_REST_Controller {

	/**
	 * Endpoint namespace.
	 *
	 * @var string
	 */
	protected $namespace = 'w2w/v1';

	/**
	 * Route base.
	 *
	 * @var string
	 */
	protected $rest_base = 'products/reviews';

	/**
	 * Register the routes for product reviews.
	 */
	public function register_routes() {
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_items' ),
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
				'args'                => $this->get_collection_params(),
			),
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'post_review' ),
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
				'args'                => array(
					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					'line_item_id' => array(
						'required' => true
					),
					'order_id' => array(
						'required' => true
					)
				)
			),
			'schema' => array( $this, 'get_public_item_schema' ),
		) );
		
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/reply', array(
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'post_reply' ),
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
				'args'                => array(
					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					'comment_parent' => array(
						'required' => true
					),
					'product_id' => array(
						'required' => true
					)
				)
			),
			'schema' => array( $this, 'get_public_item_schema' ),
		) );
		
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/image', array(
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'post_image_for_review' ),
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
				'args'                => array(
					'comment_id' => array(
						'required' => true
					)
				)
			),
			'schema' => array( $this, 'get_public_item_schema' ),
		) );
	}

	/**
	 * Check whether a given request has permission to read webhook deliveries.
	 *
	 * @param  WP_REST_Request $request Full details about the request.
	 * @return WP_Error|boolean
	 */
	public function get_items_permissions_check( $request ) {
		return true;
	}

	/**
	 * Check if a given request has access to read a webhook develivery.
	 *
	 * @param  WP_REST_Request $request Full details about the request.
	 * @return WP_Error|boolean
	 */
	public function get_item_permissions_check( $request ) {
		return true;
	}

	/**
	 * Get all reviews from a product.
	 *
	 * @param WP_REST_Request $request
	 * @return array
	 */
	public function get_items( $request ) {
		$product = get_post( (int) $request['product_id'] );
		$number = isset( $request['number'] ) ? absint( $request['number'] ) : 10;
		$paged = isset( $request['page'] ) ? absint( $request['page'] ) : 1;
		$offset = ( $paged - 1 ) * $number;

		if ( empty( $product->post_type ) || 'product' !== $product->post_type ) {
			return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product id.', 'woocommerce' ), array( 'status' => 404 ) );
		}

		$reviews = get_approved_comments( $product->ID, array(
			'parent' => isset( $request['parent'] ) ? absint( $request['parent'] ) : 0,
			'order' => 'DESC',
			'number' => $number,
			'offset' => $offset
		) );
		$data    = array();
		foreach ( $reviews as $review_data ) {
			$review = $this->prepare_item_for_response( $review_data, $request );
			$review = $this->prepare_response_for_collection( $review );
			$data[] = $review;
		}

		return rest_ensure_response( $data );
	}
	
	/**
	 * Create a review for a product.
	 *
	 * @param WP_REST_Request $request
	 * @return array
	 */
	public function post_review( $request ) {
		
		$settings = get_option( 'w2w-settings' );
		$line_item_id = $request['line_item_id'];
		$order_id = $request['order_id'];
		$order = wc_get_order( $order_id );
		
		if( ! is_user_logged_in() ) {
			return new WP_Error( 'need_login', '请登录后继续操作', array( 'status' => rest_authorization_required_code() ) );
		}
		
		if( ! $order || $order->get_user_id() != get_current_user_id() ) {
			return new WP_Error( 'w2w_order_invalid_id', '无效的订单ID', array( 'status' => 404 ) );
		}
		
		if( $order->get_status() != 'completed' ) {
			return new WP_Error( 'w2w_order_status_invalid', '订单状态错误' );
		}
		
		if( ! empty( $settings['allow_review_in_months'] ) ) {
			$allow_review_in_months = absint( $settings['allow_review_in_months'] );
			if( $order->get_date_completed()->getTimestamp() < time() - ( MONTH_IN_SECONDS * $allow_review_in_months ) ) {
				return new WP_Error( 'w2w_review_expired', '订单评价已过期' );
			}
		}
		
		$reviewed = get_post_meta( $order_id, 'reviewed', true );
		if( $reviewed ) {
			return new WP_Error( 'w2w_order_reviewed', '该订单所有产品已评价过' );
		}
		
		if( empty( $request['comment'] ) ) {
			return new WP_Error( 'w2w_review_content_empty', '请输入评价内容' );
		}
		
		$line_items = $order->get_items();
		$line_item = $line_items[ $line_item_id ];
		$product_id = $line_item->get_product_id();
		$reviewed_line_items = get_post_meta( $order_id, 'reviewed_line_items', true );
		if( ! $reviewed_line_items ) $reviewed_line_items = array();
		if( in_array( $line_item_id, $reviewed_line_items ) ) {
			return new WP_Error( 'w2w_order_line_item_reviewed', '该产品已评价过' );
		}
		
		$request['comment_post_ID'] = $product_id;
		$_POST['comment_post_ID'] = $product_id;
		
		$comment = wp_handle_comment_submission( $request );
		
		if( ! is_wp_error( $comment ) ) {
			
			$reviewed_line_items[] = $line_item_id;
			update_post_meta( $order_id, 'reviewed_line_items', $reviewed_line_items );
			
			if( count( $order->get_items() ) == count( $reviewed_line_items ) ) {
				update_post_meta( $order_id, 'reviewed', true );
			}
			$delivery = $this->prepare_item_for_response( $comment, $request );
			$comment = rest_ensure_response( $delivery );
		}

		return $comment;
	}
	
	// 回复评价
	public function post_reply( $request ) {
		
		$product_id = $request['product_id'];
		
		if( ! is_user_logged_in() ) {
			return new WP_Error( 'need_login', '请登录后继续操作', array( 'status' => rest_authorization_required_code() ) );
		}
		
		if( empty( $request['comment'] ) ) {
			return new WP_Error( 'w2w_review_content_empty', '请输入回复内容' );
		}
		
		
		$request['comment_post_ID'] = $product_id;
		$_POST['comment_post_ID'] = $product_id;
		
		$comment = wp_handle_comment_submission( $request );
		
		if( ! is_wp_error( $comment ) ) {
			
			$delivery = $this->prepare_item_for_response( $comment, $request );
			$comment = rest_ensure_response( $delivery );
		}

		return $comment;
	}
	
	// 评价图片
	public function post_image_for_review( $request ) {
		
		$settings = get_option( 'w2w-settings' );
		$comment_id = $request['comment_id'];
		$comment = get_comment( $comment_id );
		
		if( ! is_user_logged_in() ) {
			return new WP_Error( 'need_login', '请登录后继续操作', array( 'status' => rest_authorization_required_code() ) );
		}
		
		if( is_null( $comment ) || $comment->user_id != get_current_user_id() ) {
			return new WP_Error( 'w2w_comment_invalid_id', '无效的ID', array( 'status' => 404 ) );
		}
		
		$w2w_image = get_comment_meta( $comment_id, 'w2w_image' );
		$w2w_image_count = $w2w_image ? count( $w2w_image ) : 0;
		if( $w2w_image_count >= ! empty( $settings['review_images_limit'] ) ? absint( $settings['review_images_limit'] ) : 6 ) {
			return new WP_Error( 'w2w_comment_images_reached_limit', '评价图片超过限制' );
		}
		
		// 处理图片
		if ( ! function_exists( 'wp_handle_upload' ) ) {
			require_once( ABSPATH . 'wp-admin/includes/file.php' );
		}
		$uploadedfile = $_FILES['image'];
		$upload_overrides = array( 'test_form' => false );
		$movefile = wp_handle_upload( $uploadedfile, $upload_overrides );
		
		if ( $movefile && ! isset( $movefile['error'] ) ) {
			
			add_comment_meta( $comment_id, 'w2w_image', $movefile['url'] );
			
			// 插入到媒体库
			if( isset( $settings['media_show_review_images'] ) ) {
				
				$filename = $movefile['file'];
				
				// Check the type of file. We'll use this as the 'post_mime_type'.
				$filetype = wp_check_filetype( basename( $filename ), null );

				// Get the path to the upload directory.
				$wp_upload_dir = wp_upload_dir();

				// Prepare an array of post data for the attachment.
				$attachment = array(
					'guid'           => $wp_upload_dir['url'] . '/' . basename( $filename ), 
					'post_mime_type' => $filetype['type'],
					'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
					'post_content'   => '',
					'post_status'    => 'inherit'
				);
				
				// Insert the attachment.
				$attach_id = wp_insert_attachment( $attachment, $filename, 0 );

				// Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
				require_once( ABSPATH . 'wp-admin/includes/image.php' );

				// Generate the metadata for the attachment, and update the database record.
				$attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
				wp_update_attachment_metadata( $attach_id, $attach_data );
			}
			return array( 'success' => true );
		} else {
			return new WP_Error( 'w2w_review_image_upload_failed', $movefile['error'] );
		}
	}

	/**
	 * Prepare a single product review output for response.
	 *
	 * @param WP_Comment $review Product review object.
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response $response Response data.
	 */
	public function prepare_item_for_response( $review, $request ) {
		
		$avatar_url = get_user_meta( $review->user_id, 'w2w_avatar', true );
		if( ! $avatar_url ) {
			$avatar_url = get_avatar_url( $review );
		}
		
		$children = array();
		
		if( ! isset( $request['parent'] ) ) {
			$children = $review->get_children( array( 'number' => isset( $request['number'] ) ? absint( $request['number'] ) : 10 ) );
			foreach( $children as &$child ) {
				$item = $this->prepare_item_for_response( $child, $request );
				$child = $item->get_data();
			}
		}
		
		$official = get_comment_meta( $review->comment_ID, 'official', true );
		$is_official = $official ? true : false;

		$data = array(
			'id'           => (int) $review->comment_ID,
			'date_created' => get_date_from_gmt( wc_rest_prepare_date_response( $review->comment_date_gmt ), 'Y-m-d' ),
			'review'       => $review->comment_content,
			'rating'       => (int) get_comment_meta( $review->comment_ID, 'rating', true ),
			'name'         => $review->comment_author,
			'images'       => get_comment_meta( $review->comment_ID, 'w2w_image' ),
			'avatar'       => $avatar_url,
			'official'     => $is_official,
			'children'     => array_values( $children ),
			//'email'        => $review->comment_author_email,
			//'verified'     => wc_review_is_from_verified_owner( $review->comment_ID ),
		);

		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
		$data    = $this->add_additional_fields_to_object( $data, $request );
		$data    = $this->filter_response_by_context( $data, $context );

		// Wrap the data in a response object.
		$response = rest_ensure_response( $data );

		/**
		 * Filter product reviews object returned from the REST API.
		 *
		 * @param WP_REST_Response $response The response object.
		 * @param WP_Comment       $review   Product review object used to create response.
		 * @param WP_REST_Request  $request  Request object.
		 */
		return apply_filters( 'woocommerce_rest_prepare_product_review', $response, $review, $request );
	}

	/**
	 * Get the Product Review's schema, conforming to JSON Schema.
	 *
	 * @return array
	 */
	public function get_item_schema() {
		$schema = array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'product_review',
			'type'       => 'object',
			'properties' => array(
				'id' => array(
					'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
					'type'        => 'integer',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'date_created' => array(
					'description' => __( "The date the review was created, in the site's timezone.", 'woocommerce' ),
					'type'        => 'date-time',
					'context'     => array( 'view', 'edit' ),
					'readonly'    => true,
				),
				'rating' => array(
					'description' => __( 'Review rating (0 to 5).', 'woocommerce' ),
					'type'        => 'integer',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'name' => array(
					'description' => __( 'Reviewer name.', 'woocommerce' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'email' => array(
					'description' => __( 'Reviewer email.', 'woocommerce' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'verified' => array(
					'description' => __( 'Shows if the reviewer bought the product or not.', 'woocommerce' ),
					'type'        => 'boolean',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
			),
		);

		return $this->add_additional_fields_schema( $schema );
	}

	/**
	 * Get the query params for collections.
	 *
	 * @return array
	 */
	public function get_collection_params() {
		return array(
			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
		);
	}
}
