<?php
/**
 * Class responsible for communicating with Boostsite API.
 */

namespace BoostsiteAIContentGenerator\Api;

use Exception;
use BoostsiteAIContentGenerator\Boostsite;

if ( ! class_exists( 'BoostsiteController' ) ) {
	/**
	 * Boostsite API controller.
	 */
	class BoostsiteController extends \WP_REST_Controller {

		/**
		 * The application domain.
		 *
		 * @var string
		 */
		private $prefix;

		/**
		 * Initialize this class.
		 */
		public function __construct() {
			$this->prefix    = \BoostsiteAIContentGenerator\Main::PREFIX;
			$this->namespace = $this->prefix . '/v1';
			$this->rest_base = 'boostsite';
		}

		/**
		 * Register the routes.
		 *
		 * @return void
		 */
		public function register_routes() {
			// Register generate topic route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/generate_topic',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'generate_topic' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(),
				)
			);

			// Register generate topic route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/schedules',
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'schedules' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(
						'schedule_id' => array(
							'required'          => false,
							'validate_callback' => function ( $param, $request, $key ) {
								return is_string( $param );
							},
						),
						'action'      => array(
							'required'          => true,
							'validate_callback' => function ( $param, $request, $key ) {
								return is_string( $param );
							},
						),
						'schedule'    => array(
							'required'          => false,
							'validate_callback' => function ( $param, $request, $key ) {
								return is_array( $param );
							},
						),
					),
				)
			);

			// Register get subscription details route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/subscription_details',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'subscription_details' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(),
				)
			);

			// Register cancel subscription route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/cancel_subscription',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'cancel_subscription' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(),
				)
			);

			// Register get user route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/get_user',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_user' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(),
				)
			);

			// Register get schedules route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/get_schedules',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_schedules' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(),
				)
			);

			// Register get schedules route.
			register_rest_route(
				$this->namespace,
				'/' . $this->rest_base . '/generate_stripe_url',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'generate_stripe_url' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => array(),
				)
			);
		}

		/**
		 * Get the endpoint.
		 *
		 * @return string the full endpoint
		 */
		public function get_endpoint() {
			// example: myplugin/v1/settings.
			return $this->namespace . '/' . $this->rest_base;
		}

		/**
		 * Generate site topic.
		 *
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		public function generate_topic() {
			// Check if meta description is set.
			$meta_desc = get_bloginfo( 'description' );

			if ( empty( $meta_desc ) ) {
				return $this->create_success_response( '' );
			}

			return $this->handle_api_request( 'generate_topic', 'generate_topic' );
		}

		/**
		 * Performs actions on schedules
		 *
		 * @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.
		 */
		public function schedules( \WP_REST_Request $request ) {
			try {
				$params        = $request->get_json_params();
				$boostsite_api = new Boostsite();

				// Call correct method Boostsite API.
				switch ( $params['action'] ) {
					case 'delete':
						$boostsite_response = $boostsite_api->remove_schedule( $params['schedule_id'] );
						break;
					case 'edit':
						$boostsite_response = $boostsite_api->edit_schedule( $params['schedule_id'], $params['schedule'] );
						break;
					case 'add':
						$boostsite_response = $boostsite_api->add_schedule( $params['schedule'] );
						break;
					default:
						return new \WP_Error( 'schedules_error', __( 'Wrong schedules action.', 'boostsite-ai-content-generator' ), array( 'status' => 400 ) );
				}

				// Check for errors in the Boostsite API response.
				if ( is_wp_error( $boostsite_response ) ) {
					return new \WP_Error( 'boostsite_update_error', $boostsite_response->get_error_message(), array( 'status' => 500 ) );
				}

				if ( isset( $boostsite_response['info'] ) && 'error_exist' === $boostsite_response['info'] ) {
					$status_code = isset( $boostsite_response['statusCode'] ) ? $boostsite_response['statusCode'] : 400;
					return new \WP_Error( 'boostsite_api_error', $boostsite_response['data'], array( 'status' => $status_code ) );
				}

				// Return success response.
				return $this->create_success_response();
			} catch ( \Exception $e ) {
				return new \WP_Error( 'schedules_exception', $e->getMessage(), array( 'status' => 500 ) );
			} catch ( \Throwable $th ) {
				$this->log_error( $th );
				return new \WP_Error( 'schedules_error', __( 'An unexpected error occurred.', 'boostsite-ai-content-generator' ), array( 'status' => 500 ) );
			}
		}

		/**
		 * Get subscription details.
		 *
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		public function subscription_details() {
			return $this->handle_api_request( 'subscription_details', 'subscription_details' );
		}

		/**
		 * Cancel subscription.
		 *
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		public function cancel_subscription() {
			return $this->handle_api_request( 'cancel_subscription', 'cancel_subscription' );
		}

		/**
		 * Get the user schedules.
		 *
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		public function get_schedules() {
			return $this->handle_api_request( 'get_schedules', 'get_schedules' );
		}

		/**
		 * Get the user schedules.
		 *
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		public function generate_stripe_url() {
			return $this->handle_api_request( 'generate_stripe_url', 'generate_stripe_url' );
		}

		/**
		 * Get the schedules.
		 *
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		public function get_user() {
			return $this->handle_api_request( 'get_user', 'get_user' );
		}

		/**
		 * Checks if a given request has access to read the items.
		 *
		 * @param  WP_REST_Request $request Full details about the request.
		 *
		 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
		 */
		public function get_items_permissions_check( $request ) {
			// optional: check nonce
			// https://via.studio/journal/wordpress-rest-api-secure-ajax-calls-custom-endpoints
			// example: /wp-json/me/v1/endpoint/?_wpnonce=${nonce}
			// check_ajax_referer('wp_rest', '_wpnonce', true)
			// 3rd parameter (die=true) to kill rest of execution.

			// Check the nonce for security.
			$nonce = $request->get_header( 'X-WP-Nonce' );
			if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
				return new \WP_Error( 'rest_forbidden', __( 'Invalid nonce.', 'boostsite-ai-content-generator' ), array( 'status' => 403 ) );
			}

			if ( ! current_user_can( 'manage_options' ) ) {
				return new \WP_Error( 'rest_forbidden', __( 'Sorry, you cannot update settings.', 'boostsite-ai-content-generator' ), array( 'status' => 403 ) );
			}

			// since success, we response with next noonce.
			header( 'X-WP-Nonce: ' . wp_create_nonce( 'wp_rest' ) );

			return true;
		}

		/**
		 * Handle API requests and responses.
		 *
		 * @param string $api_method The API method to call.
		 * @param string $method_name The API method name.
		 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
		 */
		private function handle_api_request( $api_method, $method_name = 'api' ) {
			try {
				// Get Boostsite API response.
				$boostsite_api      = new Boostsite();
				$boostsite_response = $boostsite_api->$api_method();

				// Check for errors in the Boostsite API response.
				if ( is_wp_error( $boostsite_response ) ) {
					return new \WP_Error( 'boostsite_update_error', $boostsite_response->get_error_message(), array( 'status' => 500 ) );
				}

				if ( isset( $boostsite_response['info'] ) && 'error_exist' === $boostsite_response['info'] ) {
					$status_code = isset( $boostsite_response['statusCode'] ) ? $boostsite_response['statusCode'] : 400;
					return new \WP_Error( 'boostsite_api_error', $boostsite_response['data'], array( 'status' => $status_code ) );
				}

				// Return success response.
				return $this->create_success_response( $boostsite_response );
			} catch ( \Exception $e ) {
				return new \WP_Error( $method_name . '_exception', $e->getMessage(), array( 'status' => 500 ) );
			} catch ( \Throwable $th ) {
				$this->log_error( $th );
				return new \WP_Error( $method_name . '_error', __( 'An unexpected error occurred.', 'boostsite-ai-content-generator' ), array( 'status' => 500 ) );
			}
		}

		/**
		 * Create a success response with a nonce.
		 *
		 * @param mixed $data Data to send in the response.
		 *
		 * @return WP_REST_Response
		 */
		private function create_success_response( $data = null ) {
			$response = array(
				'success' => true,
				'nonce'   => wp_create_nonce( 'wp_rest' ),
			);

			if ( $data ) {
				$response['data'] = $data;
			}

			return rest_ensure_response( $response );
		}

		/**
		 * Log errors if debugging is enabled.
		 *
		 * @param \Throwable $th Throwable instance.
		 */
		private function log_error( \Throwable $th ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG && defined( 'BOOSTSITE_DEBUG' ) && BOOSTSITE_DEBUG ) {
				error_log( 'Error: ' . $th->getMessage() . ' in file: ' . $th->getFile() . ' on line: ' . $th->getLine() );
			}
		}
	}
}
