<?php
/**
 * REST API: CoCart_REST_Store_V2_Controller class
 *
 * @author  Sébastien Dumont
 * @package CoCart\API\v2
 * @since   3.0.0 Introduced.
 * @version 5.0.0
 * @license GPL-3.0
 */

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

class_alias( 'CoCart_REST_Store_V2_Controller', 'CoCart_Store_V2_Controller' );

/**
 * Controller for returning store details.
 *
 * This REST API controller handles the request to return store details
 * and all public routes via "cocart/v2/store" endpoint.
 *
 * @since 3.0.0 Introduced.
 */
class CoCart_REST_Store_V2_Controller {

	/**
	 * Route namespace. - Remove once new route registry is completed.
	 *
	 * @var string
	 */
	protected $namespace = 'cocart/v2';

	/**
	 * Route base. - Replaced with `get_path()`
	 *
	 * @var string
	 */
	protected $rest_base = 'store';

	/**
	 * Version of route.
	 */
	protected $version = 'v2';

	/**
	 * Get version of route. - Remove once route abstract is created to extend from.
	 */
	public function get_version() {
		return $this->version;
	}

	/**
	 * Get the path of this REST route.
	 *
	 * @return string
	 */
	public function get_path() {
		return self::get_path_regex();
	}

	/**
	 * Get the path of this rest route.
	 *
	 * @return string
	 */
	public static function get_path_regex() {
		return '/store';
	}

	/**
	 * Get method arguments for this REST route.
	 *
	 * @return array An array of endpoints.
	 */
	public function get_args() {
		return array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_store' ),
				'permission_callback' => '__return_true',
			),
			'allow_batch' => array( 'v1' => true ),
			'schema'      => array( $this, 'get_public_item_schema' ),
		);
	} // END get_args()

	/**
	 * Register routes.
	 *
	 * @access public
	 *
	 * @since 3.0.0 Introduced
	 * @since 3.1.0 Added schema information.
	 *
	 * @ignore Function ignored when parsed into Code Reference.
	 */
	public function register_routes() {
		cocart_deprecated_function( __FUNCTION__, '5.0.0' );

		// Get Store - cocart/v2/store (GET).
		register_rest_route(
			$this->namespace,
			$this->get_path(),
			$this->get_args()
		);
	} // END register_routes()

	/**
	 * Retrieves the store index.
	 *
	 * This endpoint describes the general store details.
	 *
	 * @access public
	 *
	 * @since 3.0.0 Introduced.
	 * @since 3.10.8 Version and routes are only shown if "WP_DEBUG" is true.
	 *
	 * @return WP_REST_Response The API root index data.
	 */
	public function get_store() {
		$debug = array(
			'versions' => $this->get_versions(),
			'routes'   => $this->get_routes(),
		);

		// General store data.
		$store = array(
			'title'           => get_option( 'blogname' ),
			'description'     => get_option( 'blogdescription' ),
			'home_url'        => home_url(),
			'language'        => get_bloginfo( 'language' ),
			'gmt_offset'      => get_option( 'gmt_offset' ),
			'timezone_string' => wp_timezone_string(),
			'store_address'   => $this->get_store_address(),
		);

		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			$store = array_merge( $debug, $store );
		}

		$response = rest_ensure_response( $store );

		// Add link to documentation.
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			$response->add_link( 'help', COCART_DOCUMENTATION_URL );
		}

		/**
		 * Filters the API store index data.
		 *
		 * This contains the data describing the API. This includes information
		 * about the store, routes available on the API, and a small amount
		 * of data about the site.
		 *
		 * @param WP_REST_Response $response The response object.
		 */
		return apply_filters( 'cocart_store_index', $response );
	} // END get_store()

	/**
	 * Returns the store address.
	 *
	 * @access public
	 *
	 * @return array
	 */
	public function get_store_address() {
		return apply_filters(
			'cocart_store_address',
			array(
				'address'   => get_option( 'woocommerce_store_address' ),
				'address_2' => get_option( 'woocommerce_store_address_2' ),
				'city'      => get_option( 'woocommerce_store_city' ),
				'country'   => get_option( 'woocommerce_default_country' ),
				'postcode'  => get_option( 'woocommerce_store_postcode' ),
			)
		);
	} // END get_store_address()

	/**
	 * Returns versions of CoCart plugins installed.
	 *
	 * @access protected
	 *
	 * @since 5.0.0 Introduced.
	 *
	 * @return array
	 */
	protected function get_versions() {
		return apply_filters(
			'cocart_store_versions',
			array(
				'core' => COCART_VERSION,
			)
		);
	} // END get_versions()

	/**
	 * Returns the list of all public CoCart API routes.
	 *
	 * @access protected
	 *
	 * @since 3.0.0  Introduced.
	 * @since 3.1.0  Added login, logout, cart update and product routes.
	 * @since 3.10.8 Added session routes.
	 *
	 * @return array
	 */
	protected function get_routes() {
		$prefix = trailingslashit( home_url() . '/' . rest_get_url_prefix() . '/cocart/v2/' );

		return apply_filters(
			'cocart_routes',
			array(
				'cart'                    => $prefix . 'cart',
				'cart-add-item'           => $prefix . 'cart/add-item',
				'cart-add-items'          => $prefix . 'cart/add-items',
				'cart-item'               => $prefix . 'cart/item/{item_key}',
				'cart-items'              => $prefix . 'cart/items',
				'cart-items-count'        => $prefix . 'cart/items/count',
				'cart-calculate'          => $prefix . 'cart/calculate',
				'cart-clear'              => $prefix . 'cart/clear',
				'cart-totals'             => $prefix . 'cart/totals',
				'cart-update'             => $prefix . 'cart/update',
				'login'                   => $prefix . 'login',
				'logout'                  => $prefix . 'logout',
				'products'                => $prefix . 'products',
				'products-attributes'     => $prefix . 'products/attributes',
				'products-categories'     => $prefix . 'products/categories',
				'products-reviews'        => $prefix . 'products/reviews',
				'products-tags'           => $prefix . 'products/tags',
				'products-variations'     => $prefix . 'products/{product_id}/variations',
				'products-variation'      => $prefix . 'products/{product_id}/variations/{variation_id}',
				'sessions'                => $prefix . 'sessions',
				'sessions-view-session'   => $prefix . 'sessions/{session_id}',
				'sessions-view-items'     => $prefix . 'sessions/{session_id}/items',
				'sessions-delete-session' => $prefix . 'sessions/{session_id}',
			)
		);
	} // END get_routes()

	/**
	 * Retrieves the item schema for returning the store.
	 *
	 * @access public
	 *
	 * @since 3.1.0 Introduced.
	 *
	 * @return array Public item schema data.
	 */
	public function get_public_item_schema() {
		$schema = array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'cocart_store',
			'type'       => 'object',
			'properties' => array(
				'versions'        => array(
					'description' => sprintf(
						/* translators: %s: CoCart */
						__( 'Versions of %s plugins.', 'cocart-core' ),
						'CoCart'
					),
					'type'        => 'object',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'routes'          => array(
					'description' => __( 'The routes of CoCart.', 'cocart-core' ),
					'type'        => 'object',
					'context'     => array( 'view' ),
					'properties'  => array(),
				),
				'title'           => array(
					'description' => __( 'Title of the site.', 'cocart-core' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'description'     => array(
					'description' => __( 'The site tag line.', 'cocart-core' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'home_url'        => array(
					'description' => __( 'The site home URL.', 'cocart-core' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'language'        => array(
					'description' => __( 'The site language, by default.', 'cocart-core' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'gmt_offset'      => array(
					'description' => __( 'The time offset for the timezone.', 'cocart-core' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'timezone_string' => array(
					'description' => __( 'The timezone from site settings as a string.', 'cocart-core' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'store_address'   => array(
					'description' => __( 'The full store address.', 'cocart-core' ),
					'type'        => 'object',
					'context'     => array( 'view' ),
					'properties'  => array(
						'address'   => array(
							'description' => __( 'The store address line one.', 'cocart-core' ),
							'type'        => 'string',
							'context'     => array( 'view' ),
							'readonly'    => true,
						),
						'address_2' => array(
							'description' => __( 'The store address line two.', 'cocart-core' ),
							'type'        => 'string',
							'context'     => array( 'view' ),
							'readonly'    => true,
						),
						'city'      => array(
							'description' => __( 'The store address city.', 'cocart-core' ),
							'type'        => 'string',
							'context'     => array( 'view' ),
							'readonly'    => true,
						),
						'country'   => array(
							'description' => __( 'The store address country.', 'cocart-core' ),
							'type'        => 'string',
							'context'     => array( 'view' ),
							'readonly'    => true,
						),
						'postcode'  => array(
							'description' => __( 'The store address postcode or zip.', 'cocart-core' ),
							'type'        => 'string',
							'context'     => array( 'view' ),
							'readonly'    => true,
						),
					),
				),
			),
		);

		$routes = $this->get_routes();

		if ( count( $routes ) > 0 ) {
			// Apply each route to the properties.
			foreach ( $routes as $route => $endpoint ) {
				$schema['properties']['routes']['properties'][ $route ] = array(
					'description' => sprintf(
						/* translators: %s: Route URL */
						__( 'The "%s" route URL.', 'cocart-core' ),
						$route
					),
					'type'        => 'string',
					'context'     => array( 'view' ),
					'readonly'    => true,
				);
			}
		} else {
			// Remove routes property if none exist.
			unset( $schema['properties']['routes'] );
		}

		return $schema;
	} // END get_public_item_schema()
} // END class
