<?php
/**
 * Groups Invites Rest Endpoint
 *
 * @package Nisje
 */

namespace Dekode\Nisje\Components\Rest;

defined( 'ABSPATH' ) || die( 'Shame on you' );

/**
 * Groups Invites Class
 */
class Groups_Invites_Controller extends \WP_REST_Controller {
	/**
	 * Constructor
	 */
	public function __construct() {
		$this->namespace   = nisje_get_rest_namespace();
		$this->parent_base = buddypress()->groups->id;
		$this->rest_base   = 'invites';
		$this->hook_base   = 'groups_invites';
	}

	/**
	 * Register routes
	 */
	public function register_routes() {
		register_rest_route( $this->namespace, '/' . $this->parent_base . '/' . $this->rest_base, [
			[
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_items' ],
				'permission_callback' => [ $this, 'get_items_permissions_check' ],
				'args'                => $this->get_collection_params(),
			],
			'schema' => [ $this, 'get_public_item_schema' ],
		] );
	}

	/**
	 * Get user invites
	 *
	 * @param WP_REST_Request $request Full data about the request.
	 * @return WP_Error|bool
	 */
	public function get_items_permissions_check( $request ) {
		$auth = nisje_validate_rest_authentication( $this->hook_base, 'get_items' );
		if ( is_wp_error( $auth ) ) {
			return $auth;
		}

		$user_id = bp_loggedin_user_id();
		if ( ! empty( $request['user_id'] ) ) {
			$user_id = (int) $request['user_id'];
		}

		$user_check = nisje_validate_current_user( $user_id );
		if ( is_wp_error( $user_check ) ) {
			return $user_check;
		}

		$excluded = nisje_validate_rest_excluded( $user_id );
		if ( is_wp_error( $excluded ) ) {
			return $excluded;
		}

		return true;
	}

	/**
	 * All invites for a user
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_Error|WP_REST_Response
	 */
	public function get_items( $request ) {
		$user_id = bp_loggedin_user_id();
		if ( ! empty( $request['user_id'] ) ) {
			$user_id = $request['user_id'];
		}

		$args = [
			'user_id'  => (int) $request['user_id'],
			'limit'    => (int) $request['limit'],
			'per_page' => isset( $request['per_page'] ) ? (int) $request['per_page'] : 10,
			'exclude'  => $request['exclude'],
		];

		/**
		 * Filter the query arguments for a request.
		 */
		$args = apply_filters( "nisje_rest_{$this->hook_base}_query", $args, $request );

		$retval = [];
		$groups = groups_get_invites_for_user( $args['user_id'], $args['limit'], $args['per_page'], $args['exclude'] );

		$total_invites = groups_get_invite_count_for_user( $args['user_id'] );

		foreach ( $groups['groups'] as $group ) {
			$data     = $this->prepare_item_for_response( $group, $request );
			$retval[] = $this->prepare_response_for_collection( $data );
		}

		$max_pages = ceil( $total_invites / (int) $args['per_page'] );

		$response = rest_ensure_response( $retval );
		$response->header( 'X-WP-Total', (int) $total_invites );
		$response->header( 'X-WP-TotalPages', (int) $max_pages );

		$request_params = $request->get_query_params();

		$base = add_query_arg( $request_params, rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
		$page = (int) $args['per_page'];

		if ( $page > 1 ) {
			$prev_page = $page - 1;
			if ( $prev_page > $max_pages ) {
				$prev_page = $max_pages;
			}
			$prev_link = add_query_arg( 'page', $prev_page, $base );
			$response->link_header( 'prev', $prev_link );
		}
		if ( $max_pages > $page ) {
			$next_page = $page + 1;
			$next_link = add_query_arg( 'page', $next_page, $base );
			$response->link_header( 'next', $next_link );
		}

		return $response;
	}

	/**
	 * Prepares group data for return as an object.
	 *
	 * @param stdClass        $item    Group data.
	 * @param WP_REST_Request $request The request.
	 * @param boolean         $is_raw  Optional, not used. Defaults to false.
	 * @return WP_REST_Response
	 */
	public function prepare_item_for_response( $item, $request, $is_raw = false ) {
		$schema = $this->get_item_schema();

		$data = [];

		if ( ! empty( $schema['properties']['id'] ) ) {
			$data['id'] = (int) $item->id;
		}

		if ( ! empty( $schema['properties']['creator_id'] ) ) {
			// Direct: $item->creator_id.
			$data['creator_id'] = (int) bp_get_group_creator_id( $item );
		}

		if ( ! empty( $schema['properties']['name'] ) ) {
			// Direct: $item->name.
			$data['name'] = bp_get_group_name( $item );
		}

		if ( ! empty( $schema['properties']['slug'] ) ) {
			// Direct: $item->slug.
			$data['slug'] = bp_get_group_slug( $item );
		}

		if ( ! empty( $schema['properties']['description'] ) ) {
			$data['description'] = [
				'rendered' => bp_get_group_description( $item ),
			];
		}

		if ( ! empty( $schema['properties']['parent_id'] ) ) {
			$data['parent_id'] = absint( $item->parent_id );
		}

		if ( ! empty( $schema['properties']['status'] ) ) {
			$data['status'] = bp_get_group_status( $item );
		}

		if ( ! empty( $schema['properties']['date_created'] ) ) {
			$data['date_created'] = nisje_prepare_date_response( $item->date_created );
		}

		if ( ! empty( $schema['properties']['total_member_count'] ) ) {
			$data['total_member_count'] = (int) groups_get_groupmeta( $item->id, 'total_member_count' );
		}

		if ( ! empty( $schema['properties']['color'] ) ) {
			$data['color'] = (int) groups_get_groupmeta( $item->id, 'color' );
		}

		if ( ! empty( $schema['properties']['last_activity'] ) ) {
			$data['last_activity'] = nisje_prepare_date_response( groups_get_groupmeta( $item->id, 'last_activity' ) );
		}

		if ( ! empty( $schema['properties']['avatar_urls'] ) ) {
			$data['avatar_urls'] = nisje_get_group_avatar( $item->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 );

		$response = rest_ensure_response( $data );
		$response->add_links( $this->prepare_links( $item ) );

		/**
		 * Filter value returned from the API.
		 */
		return apply_filters( "nisje_rest_prepare_{$this->hook_base}_value", $response, $item, $request );
	}

	/**
	 * Prepare links for the request.
	 *
	 * @param array $item Item.
	 * @return array Links for the given plugin.
	 */
	protected function prepare_links( $item ) {
		$base = sprintf( '/%s/%s/', $this->namespace, $this->rest_base );

		// Entity meta.
		$links = [
			'groups' => [
				'href' => rest_url( '/' . $this->namespace . '/groups/' . $item->id ),
			],
		];

		return $links;
	}

	/**
	 * Get the plugin schema, conforming to JSON Schema.
	 *
	 * @return array
	 */
	public function get_item_schema() {
		$schema = [
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => $this->hook_base,
			'type'       => 'object',
			'properties' => [
				'id'                 => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'A unique alphanumeric ID for the object.', 'nisje' ),
					'type'        => 'integer',
				],
				'creator_id'         => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'The ID for the creator of the object.', 'nisje' ),
					'type'        => 'integer',
				],
				'name'               => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'Name of the group.', 'nisje' ),
					'type'        => 'string',
				],
				'slug'               => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'The URL-friendly slug for the group.', 'nisje' ),
					'type'        => 'string',
					'arg_options' => [
						'sanitize_callback' => [ $this, 'sanitize_slug' ],
					],
				],
				'description'        => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'The description of the group.', 'nisje' ),
					'type'        => 'object',
					'properties'  => [
						'rendered' => [
							'context'     => [ 'view' ],
							'description' => esc_html__( 'HTML description of the group transformed for display.', 'nisje' ),
							'type'        => 'string',
						],
					],
				],
				'parent_id'          => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'The ID of the parent group.', 'nisje' ),
					'type'        => 'integer',
				],
				'status'             => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'The status of the group.', 'nisje' ),
					'type'        => 'string',
					'enum'        => [ 'public', 'private', 'hidden' ],
				],
				'date_created'       => [
					'context'     => [ 'view', 'edit', 'member' ],
					'description' => esc_html__( 'The date the object was published, in the site timezone.', 'nisje' ),
					'type'        => 'string',
					'format'      => 'date-time',
				],
				'last_activity'      => [
					'context'     => [ 'view', 'edit', 'member' ],
					'description' => esc_html__( 'Last activity in group', 'nisje' ),
					'type'        => 'string',
					'format'      => 'date-time',
				],
				'color'              => [
					'context'     => [ 'view' ],
					'description' => esc_html__( 'Color ID.', 'nisje' ),
					'type'        => 'integer',
				],
				'avatar_urls'        => [
					'context'     => [ 'view', 'edit', 'embed' ],
					'description' => esc_html__( 'Avatar URLs for the resource', 'nisje' ),
					'type'        => 'object',
					'readonly'    => true,
					'properties'  => nisje_get_avatar_rest_properties(),
				],
				'total_member_count' => [
					'context'     => [ 'view', 'edit', 'member' ],
					'description' => esc_html__( 'Total group members', 'nisje' ),
					'type'        => 'integer',
				],
			],
		];

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

	/**
	 * Get the query params for collections of plugins.
	 *
	 * @return array
	 */
	public function get_collection_params() {
		$params['context']['default'] = 'view';

		$params['user_id'] = [
			'description'       => esc_html__( 'A unique alphanumeric ID of the user.', 'nisje' ),
			'type'              => 'integer',
			'sanitize_callback' => 'absint',
			'validate_callback' => 'rest_validate_request_arg',
		];

		$params['limit'] = [
			'description'       => esc_html__( 'Offset the result set by a specific number of pages of results.', 'nisje' ),
			'default'           => 0,
			'type'              => 'integer',
			'sanitize_callback' => 'absint',
			'validate_callback' => 'rest_validate_request_arg',
		];

		$params['exclude'] = [
			'description'       => esc_html__( 'Ensure result set excludes specific IDs.', 'nisje' ),
			'type'              => 'array',
			'default'           => [],
			'sanitize_callback' => 'wp_parse_id_list',
		];

		$params['per_page'] = [
			'description'       => esc_html__( 'Offset the result set by a specific number of pages of results.', 'nisje' ),
			'default'           => 10,
			'type'              => 'integer',
			'sanitize_callback' => 'absint',
			'validate_callback' => 'rest_validate_request_arg',
		];

		return $params;
	}
}
