<?php
/**
 * Contains the Polls Controller Class
 *
 * @since 0.9.0
 * @package Crowdsignal_Forms\Rest_Api
 **/

namespace Crowdsignal_Forms\Rest_Api\Controllers;

use Crowdsignal_Forms\Crowdsignal_Forms;
use Crowdsignal_Forms\Models\Poll;

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

/**
 * Polls Controller Class
 *
 * Poll mutations (create, update, archive) are handled via the save_post hook
 * in Poll_Block_Synchronizer, not through REST API endpoints. This controller
 * only provides read-only endpoints for fetching poll data.
 *
 * @since 0.9.0
 **/
class Polls_Controller {
	/**
	 * The namespace.
	 *
	 * @var string
	 **/
	protected $namespace = 'crowdsignal-forms/v1';

	/**
	 * The rest api base.
	 *
	 * @var string
	 **/
	protected $rest_base = 'polls';

	/**
	 * Register the routes for fetching polls
	 *
	 * @since 0.9.0
	 **/
	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_polls' ),
					'permission_callback' => array( $this, 'get_polls_permissions_check' ),
					'args'                => $this->get_collection_params(),
				),
			)
		);

		// GET polls/:poll_id route.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<poll_id>[a-zA-Z0-9\-\_]+)',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_poll' ),
					'permission_callback' => array( $this, 'get_poll_permissions_check' ),
					'args'                => $this->get_poll_fetch_params(),
				),
			)
		);

		// GET polls/:poll_id/results route.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<poll_id>[a-zA-Z0-9\-\_]+)/results',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_poll_results' ),
					'permission_callback' => array( $this, 'get_poll_permissions_check' ),
				),
			)
		);

		// GET post-polls/:post_id/:poll_uuid route.
		register_rest_route(
			$this->namespace,
			'/post-polls/(?P<post_id>\d+)/(?P<poll_uuid>[a-zA-Z0-9\-\_]+)',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_post_poll_by_uuid' ),
					'permission_callback' => array( $this, 'get_poll_permissions_check' ),
				),
			)
		);
	}

	/**
	 * Get the polls.
	 *
	 * @since 0.9.0
	 *
	 * @return \WP_REST_Response
	 **/
	public function get_polls() {
		return rest_ensure_response( Crowdsignal_Forms::instance()->get_api_gateway()->get_polls() );
	}

	/**
	 * The permission check.
	 *
	 * @since 0.9.0
	 *
	 * @return bool
	 **/
	public function get_polls_permissions_check() {
		return true;
	}

	/**
	 * Get a poll by ID.
	 *
	 * @since 0.9.0
	 *
	 * @param \WP_REST_Request $request
	 *
	 * @return \WP_REST_Response|\WP_Error
	 **/
	public function get_poll( $request ) {
		$poll_id = $request->get_param( 'poll_id' );
		if ( null === $poll_id ) {
			return new \WP_Error(
				'invalid-poll-id',
				__( 'Invalid poll ID', 'crowdsignal-forms' ),
				array( 'status' => 400 )
			);
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$use_cached = isset( $_REQUEST['cached'] );

		if ( ! is_numeric( $poll_id ) ) {
			$poll_client_id     = $poll_id;
			$poll_saved_in_meta = Crowdsignal_Forms::instance()
				->get_post_poll_meta_gateway()
				->get_poll_data_for_poll_client_id( null, $poll_client_id );

			if ( empty( $poll_saved_in_meta ) ) {
				return $this->resource_not_found();
			}

			if ( $use_cached ) {
				return rest_ensure_response( Poll::from_array( $poll_saved_in_meta )->to_array() );
			}

			$poll_id = $poll_saved_in_meta['id'];
		}
		$poll = Crowdsignal_Forms::instance()->get_api_gateway()->get_poll( $poll_id );

		if ( is_wp_error( $poll ) ) {
			return rest_ensure_response( $poll );
		}

		return rest_ensure_response( $poll->to_array() );
	}

	/**
	 * Get a post's poll given the post id and poll uuid.
	 *
	 * @since 0.9.0
	 *
	 * @param \WP_REST_Request $request The HTTP request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 **/
	public function get_post_poll_by_uuid( $request ) {
		$post_id   = $request->get_param( 'post_id' );
		$poll_uuid = $request->get_param( 'poll_uuid' );

		if ( null === $post_id || ! is_numeric( $post_id ) ) {
			return new \WP_Error(
				'invalid-post-id',
				__( 'Invalid post ID', 'crowdsignal-forms' ),
				array( 'status' => 400 )
			);
		}

		$the_post = get_post( $post_id );

		if ( empty( $the_post ) ) {
			return $this->resource_not_found();
		}

		if ( null === $poll_uuid ) {
			return new \WP_Error(
				'invalid-poll-id',
				__( 'Invalid poll ID', 'crowdsignal-forms' ),
				array( 'status' => 400 )
			);
		}

		$poll_saved_in_meta = Crowdsignal_Forms::instance()
			->get_post_poll_meta_gateway()
			->get_poll_data_for_poll_client_id( $post_id, $poll_uuid );

		if ( empty( $poll_saved_in_meta ) || ! isset( $poll_saved_in_meta['id'] ) ) {
			return $this->resource_not_found();
		}

		return rest_ensure_response( $poll_saved_in_meta );
	}

	/**
	 * Get poll results by ID.
	 *
	 * @since 0.9.0
	 *
	 * @param \WP_REST_Request $request
	 *
	 * @return \WP_REST_Response
	 **/
	public function get_poll_results( $request ) {
		$poll_id = $request->get_param( 'poll_id' );
		return rest_ensure_response( Crowdsignal_Forms::instance()->get_api_gateway()->get_poll_results( $poll_id ) );
	}

	/**
	 * The get-a-poll by ID permission check.
	 *
	 * @since 0.9.0
	 *
	 * @return bool
	 **/
	public function get_poll_permissions_check() {
		return true;
	}

	/**
	 * Gets the collection params.
	 *
	 * @since 0.9.0
	 * @return array
	 */
	protected function get_collection_params() {
		return array();
	}

	/**
	 * Returns a validator array for the get-a-poll by ID params.
	 *
	 * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
	 * @since 0.9.0
	 * @return array
	 */
	protected function get_poll_fetch_params() {
		return array(
			'poll_id' => array(
				'validate_callback' => function ( $param, $request, $key ) {
					return true;
				},
			),
		);
	}

	/**
	 * For not-found.
	 *
	 * @since 0.9.0
	 * @return \WP_Error
	 */
	private function resource_not_found() {
		return new \WP_Error(
			'resource-not-found',
			__( 'Resource not found', 'crowdsignal-forms' ),
			array( 'status' => 404 )
		);
	}
}
