<?php
/**
 * FE Admin Email controller.
 *
 * @since 2.5.0
 */

declare( strict_types=1 );
namespace FeData\FastEvents\RestAPI\Public;

defined( 'ABSPATH' ) || exit;

use FeData\FastEvents\Helpers\AuthHelper;
use stdClass;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;


/**
 * FE Admin Email controller class.
 */
class EmailsController extends WP_REST_Controller {

	/**
	 * Admin Email controller constructor.
	 *
	 * @param AuthHelper $auth The auth helper instance.
	 *
	 * @since 2.5.0
	 */
	public function __construct( private readonly AuthHelper $auth ) {
		$this->namespace = 'fast-events/v1';
		$this->rest_base = 'admin/emails';
	}


	/**
	 * Register the routes for the objects of the controller.
	 *
	 * @since 2.5.0
	 */
	public function register_routes(): void {

		// Get all emails.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_items' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_EMAIL );
					},
					'args'                => $this->get_collection_params(),
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/order/(?P<id>[\d]+)',
			array(
				'args'   => array(
					'id' => array(
						'description'       => __( 'The unique id of the order', 'fast-events' ),
						'type'              => 'integer',
						'required'          => true,
						'sanitize_callback' => 'absint',
					),
				),
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_order_emails' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_EMAIL );
					},
					'args'                => array(
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					),
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>[\d]+)',
			array(
				'args'   => array(
					'id' => array(
						'description'       => __( 'The unique id of the email', 'fast-events' ),
						'type'              => 'integer',
						'required'          => true,
						'sanitize_callback' => 'absint',
					),
				),
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_item' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_EMAIL );
					},
				),
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_item' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_EMAIL_DELETE );
					},
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);
	}


	/**
	 * Get the authorization for the Emails endpoints.
	 *
	 * @param int $action The action on the controller.
	 * @return WP_Error|bool
	 *
	 * @since 2.5.0
	 */
	public function fast_events_admin_permissions( int $action ): WP_Error|bool {
		return $this->auth->authorize( $action );
	}


	/**
	 * Get all Emails.
	 *
	 * @param WP_REST_Request $request Request instance.
	 * @return WP_REST_Response|WP_Error|array
	 *
	 * @since 2.5.0
	 */
	public function get_items( $request ): WP_Error|WP_REST_Response|array {
		global $wpdb;

		// Get all emails the user is authorized for.
		$auth_query = $this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_EVENTS );
		$auth_query = str_replace( 'id', 'event_id', $auth_query ); // Hack.

		$result = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}fe_event_email_log" . $auth_query . ' ORDER BY id DESC' // phpcs:ignore
			)
		);

		$emails = array();

		foreach ( $result as $item ) {
			$data     = $this->prepare_item_for_response( $item, $request );
			$emails[] = $this->prepare_response_for_collection( $data );
		}

		$response = rest_ensure_response( $emails );

		// Generate the totals headers.
		$response->header( 'X-WP-Total', count( $emails ) );
		$response->header( 'X-WP-TotalPages', 1 );

		return $response;
	}


	/**
	 * Retrieve a single email.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
	 *
	 * @since 2..5.0
	 */
	public function get_item( $request ): WP_Error|WP_REST_Response {
		global $wpdb;

		// Check the event authorization.
		$resp = $this->auth->check_event_authorization( absint( $request['id'] ) );
		if ( is_wp_error( $resp ) ) {
			return $resp;
		}

		// Look up the event.
		$email_entry = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}fe_event_email_log WHERE id = %d",
				$request['id']
			)
		);
		if ( empty( $email_entry ) ) {
			return new WP_Error( 'not_found', __( 'Email entry not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		return rest_ensure_response( $this->prepare_item_for_response( $email_entry, $request ) );
	}


	/**
	 * Retrieve all emails entries of an order.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error|array Response object on success, or WP_Error object on failure.
	 *
	 * @since 2.5.0
	 */
	public function get_order_emails( WP_REST_Request $request ): WP_Error|WP_REST_Response|array {
		global $wpdb;

		// Get all events the user is authorized for.
		$auth_query = $this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_ORDER_LOOKUP );

		$result = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}fe_event_email_log WHERE order_id = %d" . $auth_query . ' ORDER BY id DESC', // phpcs:ignore
				$request['id']
			)
		);

		$emails = array();

		foreach ( $result as $item ) {
			$data     = $this->prepare_item_for_response( $item, $request );
			$emails[] = $this->prepare_response_for_collection( $data );
		}

		$response = rest_ensure_response( $emails );

		// Generate the totals headers.
		$response->header( 'X-WP-Total', count( $emails ) );
		$response->header( 'X-WP-TotalPages', 1 );

		return $response;
	}


	/**
	 * Delete a single email entry.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error|bool|array|stdClass Response object on success, or WP_Error object on failure.
	 *
	 * @since 2.5.0
	 */
	public function delete_item( $request ): WP_Error|WP_REST_Response|bool|array|stdClass {
		global $wpdb;

		// Get all events the user is authorized for.
		$auth_query = $this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_ORDER_LOOKUP );

		$email_entry = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}fe_event_email_log WHERE id = %d" . $auth_query, // phpcs:ignore
				$request['id']
			)
		);
		if ( empty( $email_entry ) ) {
			return new WP_Error( 'not_found', __( 'Email entry not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->prefix}fe_event_email_log WHERE id = %d" . $auth_query, // phpcs:ignore
				$request['id']
			)
		);

		$request->set_param( 'context', 'view' );

		$previous = $this->prepare_item_for_response( $email_entry, $request );

		$response = new WP_REST_Response();
		$response->set_data(
			array(
				'deleted'  => true,
				'previous' => $previous->get_data(),
			)
		);

		return $response;
	}


	/**
	 * Retrieves the query params for the collections.
	 *
	 * @return array Query parameters for the collection.
	 *
	 * @since 2.5.0
	 */
	public function get_collection_params(): array {
		return array(
			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
		);
	}


	/**
	 * Prepares a single email entry output for response.
	 *
	 * @param mixed           $item    Scan key object.
	 * @param WP_REST_Request $request Request object.
	 *
	 * @return WP_REST_Response Response object.
	 *
	 * @since 2.5.0
	 */
	public function prepare_item_for_response( $item, $request ): WP_REST_Response {

		$data   = array();
		$fields = $this->get_fields_for_response( $request );

		if ( rest_is_field_included( 'id', $fields ) ) {
			$data['id'] = (int) $item->id;
		}

		if ( rest_is_field_included( 'event_id', $fields ) ) {
			$data['event_id'] = (int) $item->event_id;
		}

		if ( rest_is_field_included( 'order_id', $fields ) ) {
			$data['order_id'] = (int) $item->order_id;
		}

		if ( rest_is_field_included( 'date_created', $fields ) ) {
			$data['date_created'] = $item->date_created;
		}

		if ( rest_is_field_included( 'date_modified', $fields ) ) {
			$data['date_modified'] = $item->date_modified;
		}

		if ( rest_is_field_included( 'provider_id', $fields ) ) {
			$data['provider_id'] = $item->provider_id;
		}

		if ( rest_is_field_included( 'email_type', $fields ) ) {
			$data['email_type'] = $item->email_type;
		}

		if ( rest_is_field_included( 'provider_email_id', $fields ) ) {
			$data['provider_email_id'] = $item->provider_email_id;
		}

		if ( rest_is_field_included( 'sender_email', $fields ) ) {
			$data['sender_email'] = $item->sender_email;
		}

		if ( rest_is_field_included( 'receiver_email', $fields ) ) {
			$data['receiver_email'] = $item->receiver_email;
		}

		if ( rest_is_field_included( 'email_subject', $fields ) ) {
			$data['email_subject'] = $item->email_subject;
		}

		if ( rest_is_field_included( 'email_events', $fields ) ) {
			$data['email_events'] = $item->email_events;
		}

		$context = ! empty( $request['context'] ) ? $request['context'] : 'embed';

		$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 );

		if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
			$response->add_links( $this->prepare_links( $item, $request ) );
		}

		return $response;
	}


	/**
	 * Prepares links for the email request.
	 *
	 * @param stdClass        $field   Email object.
	 * @param WP_REST_Request $request Request object.
	 *
	 * @return array Links for the given order.
	 *
	 * @since 2.0
	 */
	protected function prepare_links( stdClass $field, WP_REST_Request $request ): array {
		if ( str_contains( $request->get_route(), '/order/' ) ) {
			return array(
				'self'       => array(
					'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $field->id ) ),
				),
				'collection' => array(
					'href' => rest_url( sprintf( '%s/%s/order/%d', $this->namespace, $this->rest_base, $field->order_id ) ),
				),
			);
		} else {
			return array(
				'self'       => array(
					'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $field->id ) ),
				),
				'collection' => array(
					'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
				),
			);
		}
	}


	/**
	 * Return the emails' schema.
	 *
	 * @return array
	 *
	 * @since 2.5.0
	 */
	public function get_item_schema(): array {
		if ( $this->schema ) {
			return $this->add_additional_fields_schema( $this->schema );
		}

		$this->schema = array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'emails',
			'type'       => 'object',
			'properties' => array(
				'id'                => array(
					'description' => __( 'The unique id of the email.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'event_id'          => array(
					'description' => __( 'The unique id of the event.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'order_id'          => array(
					'description' => __( 'The unique id of the order.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'date_created'      => array(
					'description' => __( 'The creation date of the email entry.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'date_modified'     => array(
					'description' => __( 'The last modification date of the email entry.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'provider_id'       => array(
					'description' => __( 'The unique id of the email provider.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'email_type'        => array(
					'description' => __( 'Type of email.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'provider_email_id' => array(
					'description' => __( 'The unique id that the provider uses for the email.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'sender_email'      => array(
					'description' => __( 'The emailaddress of the sender.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'receiver_email'    => array(
					'description' => __( 'The emailaddress of the recipient.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'email_subject'     => array(
					'description' => __( 'The subject of the email.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'email_events'      => array(
					'description' => __( 'A JSON array of email events.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
			),
		);

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