<?php
/**
 * Class responsible for Rest API that the plugin exposes.
 */

namespace BoostsiteAIContentGenerator\Api;

use DateTime;
use Humbug\PhpScoper\Scoper\NullScoper;
use WP_REST_Controller;

require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';

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

/**
 * Extending REST API framework of WordPress to be used by Boostsite API
 */
if ( ! class_exists( 'RestApi' ) ) {

	/**
	 * RestApi class.
	 */
	class RestApi extends WP_REST_Controller {

		/**
		 * Settings.
		 *
		 * @var SettingController
		 */
		private $settings;

		/**
		 * Constructor
		 *
		 * @return void
		 */
		public function __construct() {
			header( 'Access-Control-Allow-Origin: *' );
			$this->register_routes();

			$this->settings = new SettingController();
		}

		/**
		 * REST API routes
		 *
		 * @return void
		 */
		public function register_routes() {
			$version   = '1';
			$namespace = 'boostsite/v' . $version;

			// Register check plugin route.
			register_rest_route(
				$namespace,
				'/check_plugin',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'callback_check_plugin' ),
					'permission_callback' => array( $this, 'authenticate' ),
				)
			);

			// Register get post route.
			register_rest_route(
				$namespace,
				'/get_post',
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'callback_get_post' ),
					'permission_callback' => array( $this, 'authenticate' ),
					'args'                => array(
						'post_id'         => array(
							'required'          => true,
							'validate_callback' => function ( $param, $request, $key ) {
								return is_numeric( $param );
							},
						),
					),
				)
			);

			// Register plan post route.
			register_rest_route(
				$namespace,
				'/plan_post',
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'callback_post_order' ),
					'permission_callback' => array( $this, 'authenticate' ),
					'args'                => array(
						'post_title'      => array(
							'required'          => true,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_content'    => array(
							'required'          => true,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_author'     => array(
							'required'          => false,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_publish_at' => array(
							'required'          => true,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_keywords'     => array(
							'required'          => false,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
					),
				)
			);

			// Register add meta data route.
			register_rest_route(
				$namespace,
				'/add_content',
				array(
					'methods'             => \WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'callback_put_article' ),
					'permission_callback' => array( $this, 'authenticate' ),
					'args'                => array(
						'post_id'         => array(
							'required'          => true,
							'validate_callback' => function ( $param, $request, $key ) {
								return is_numeric( $param );
							},
						),
						'post_content'    => array(
							'required'          => true,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_image'      => array(
							'required'          => false,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_meta_title' => array(
							'required'          => false,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_category'   => array(
							'required'          => false,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
						'post_meta_desc'  => array(
							'required'          => false,
							'validate_callback' => array( $this, 'is_string_validation' ),
						),
					),
				)
			);

			// Register publish post route.
			register_rest_route(
				$namespace,
				'/publish',
				array(
					'methods'             => \WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'callback_publish_article' ),
					'permission_callback' => array( $this, 'authenticate' ),
					'args'                => array(
						'post_id' => array(
							'required'          => true,
							'validate_callback' => function ( $param, $request, $key ) {
								return is_numeric( $param );
							},
						),
					),
				)
			);
		}

		/**
		 * Check if the plugin is installed and activated.
		 *
		 * @return \WP_REST_Response
		 * @throws \Exception Error if fails post insert.
		 */
		public function callback_check_plugin() {
			try {
				// Check if the plugin is installed and activated.
				if ( ! function_exists( 'is_plugin_active' ) ) {
					include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
				}
				
				$plugin_path = 'boostsite-ai-content-generator/boostsite-ai-content-generator.php';
				$is_active   = is_plugin_active( $plugin_path );

				if ( ! $is_active ) {
					throw new \Exception( 'Plugin is not activated.' );
				}

				$response = array(
					'data' => 'success'
				);

				return new \WP_REST_Response( $response, 200 );
			} catch ( \Throwable $th ) {
				$this->log_debug( 'Error while checking plugin: ' . $th->getMessage() );

				// Handle error - plugin not activated is a service unavailable error
				return new \WP_REST_Response( array( 'error' => 'Plugin check failed: ' . $th->getMessage() ), 503 );
			}
		}

		/**
		 * Check if post exists.
		 *
		 * @param  \WP_REST_Request $request API request.
		 * @return \WP_REST_Response
		 * @throws \Exception Error if fails post insert.
		 */
		public function callback_get_post( \WP_REST_Request $request ) {
			$params = $request->get_json_params();

			try {
				// Get the post.
				$post = get_post( $params['post_id'] );
				if ( ! $post ) {
					return new \WP_REST_Response( array( 'error' => 'Post not found.' ), 404 );
				}

				// Check if post is trashed.
				if ( 'trash' === $post->post_status ) {
					return new \WP_REST_Response( array( 'error' => 'Post not found.' ), 404 );
				}

				// Return post status.
				$response = array(
					'id'          => $post->ID,
					'post_title'  => $post->post_title,
					'post_status' => $post->post_status,
				);

				return new \WP_REST_Response( $response, 200 );
			} catch ( \Throwable $th ) {
				$this->log_debug( 'Error while getting post: ' . $th->getMessage() );

				// Handle error.
				return new \WP_REST_Response( array( 'error' => 'Post fetching failed: ' . $th->getMessage() ), 400 );
			}
		}


		/**
		 * Create post with future date without content
		 *
		 * @param  \WP_REST_Request $request API request.
		 * @return \WP_REST_Response
		 * @throws \Exception Error if fails post insert.
		 */
		public function callback_post_order( \WP_REST_Request $request ) {
			$params = $request->get_json_params();

			$this->log_debug( 'Creating post with params: ' . json_encode( $params ) );

			// Get the author and the user from params.
			$user   = null;
			$author = '';

			// First get the user.
			if ( isset( $params['post_author'] ) && ! empty( $params['post_author'] ) ) {
				// Get user ID.
				$user = get_user_by( 'slug', $params['post_author'] );
			} else {
				// Get author from the first schedule.
				$first_schedule = $this->settings->get_single_setting( 'schedules' )[0];
				$user           = get_user_by( 'slug', $first_schedule['author'] );
			}

			// Set the author.
			if ( $user ) {
				$author = $user->ID;
			}

			// Format the date.
			$date_time      = new DateTime( wp_strip_all_tags( $params['post_publish_at'] ) );
			$formatted_date = $date_time->format( 'Y-m-d H:i:s' );

			try {
				// Insert new post.
				$id = wp_insert_post(
					array(
						'post_title'   => wp_strip_all_tags( $params['post_title'] ),
						'post_content' => wp_kses_post( $params['post_content'] ),
						'post_status'  => 'future',
						'post_author'  => $author,
						'post_date'    => $formatted_date,
					),
					true
				);

				// Handle error.
				if ( is_wp_error( $id ) ) {
					throw new \Exception( $id->get_error_message() );
				}

				// Update the post meta for boostsite.
				update_post_meta( $id, 'wp_autopost_ai_post', true );
				update_post_meta( $id, 'wp_autopost_ai_post_status', 'schedule_generate' );

				// Add keywords.
				if ( isset( $params['post_keywords'] ) && ! empty( $params['post_keywords'] ) ) {
					// Sanitize keywords.
					$keywords = sanitize_text_field( $params['post_keywords'] );

					update_post_meta( $id, 'wp_autopost_ai_post_keywords', $keywords );
				}

				$this->log_debug( 'Created post: ' . $id );

				return new \WP_REST_Response( array( 'id' => $id ), 200 );
			} catch ( \Throwable $th ) {
				$this->log_debug( 'Error while creating post: ' . $th->getMessage() );

				// Handle error.
				return new \WP_REST_Response( array( 'error' => 'Post creation failed: ' . $th->getMessage() ), 400 );
			}
		}

		/**
		 * Add content and meta data to post
		 *
		 * @param  \WP_REST_Request $request API request.
		 * @return \WP_REST_Response
		 * @throws \Exception Error if fails updating post fields.
		 */
		public function callback_put_article( \WP_REST_Request $request ) {
			$params = $request->get_json_params();
			$data   = array();

			$this->log_debug( 'Adding content with params: ' . json_encode( $params ) );

			try {
				$post = get_post( $params['post_id'] );

				// Throw an error if the post doesnt exist.
				if ( ! $post || 'post' !== $post->post_type ) {
					throw new \Exception( 'Post not found.' );
				}

				// Throw an error if the post is published.
				if ( 'publish' === $post->post_status ) {
					throw new \Exception( 'Post is already published.' );
				}

				// Images.
				if ( ! empty( $params['post_image'] ) ) {
					// Sideload image.
					$image_id = media_sideload_image( $params['post_image'] . '&ext=.png', $params['post_id'], null, 'id' );
					if ( is_wp_error( $image_id ) ) {
						throw new \Exception( 'Image sideload failed: ' . $image_id->get_error_message() );
					}
					$data['image_id'] = $image_id;

					// Set post thumbnail.
					$thumbnail_set = set_post_thumbnail( $params['post_id'], $image_id );
					if ( ! $thumbnail_set ) {
						throw new \Exception( 'Setting post thumbnail failed.' );
					}
					$data['thumbnail_set'] = true;

					// Update image alt.
					if ( ! empty( $params['post_meta_title'] ) ) {
						$alt_updated         = update_post_meta( $image_id, '_wp_attachment_image_alt', $params['post_meta_title'] );
						$data['alt_updated'] = $alt_updated;
					}
				}

				// Set the category.
				$post_category = null;

				if ( ! empty( $params['post_category'] ) ) {
					// Get the cateogory ID.
					$post_category         = get_terms(
						array(
							'fields'     => 'ids',
							'taxonomy'   => 'category',
							'name'       => $params['post_category'],
							'hide_empty' => false,
						)
					);

					// If the category does not exist, create it.
					if ( empty( $post_category ) || is_wp_error( $post_category ) ) {
						$category_id = wp_insert_term(
							wp_strip_all_tags( $params['post_category'] ),
							'category'
						);

						if ( is_wp_error( $category_id ) ) {
							throw new \Exception( 'Category creation failed: ' . $category_id->get_error_message() );
						}

						$post_category = array( $category_id['term_id'] );
					}

					// Make sure it's an array.
					if ( ! is_array( $post_category ) ) {
						$post_category = array( $post_category );
					}

					$data['post_category'] = $post_category;
				}

				// Update post.
				$post_id = wp_update_post(
					array(
						'ID'            => $params['post_id'],
						'post_content'  => $params['post_content'],
						'post_category' => $post_category,
					),
					true // Return WP_Error on failure.
				);

				if ( is_wp_error( $post_id ) ) {
					throw new \Exception( 'Post update failed: ' . $post_id->get_error_message() );
				}
				$data['post_id'] = $post_id;

				// Check for SEO plugins and update meta.
				$active_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
				if ( ( in_array( 'wordpress-seo/wp-seo.php', $active_plugins ) || in_array( 'all-in-one-seo-pack/all_in_one_seo_pack.php', $active_plugins ) ) && ! empty( $params['post_meta_desc'] ) && ! empty( $params['post_meta_title'] ) ) {
					$meta_desc_updated  = update_post_meta( $params['post_id'], '_yoast_wpseo_metadesc', $params['post_meta_desc'] );
					$meta_title_updated = update_post_meta( $params['post_id'], '_yoast_wpseo_title', $params['post_meta_title'] );

					$data['meta_desc_updated']  = $meta_desc_updated;
					$data['meta_title_updated'] = $meta_title_updated;
				}

				// Update the post meta for boostsite.
				update_post_meta( $post_id, 'wp_autopost_ai_post_status', 'schedule_publish' );

				$this->log_debug( 'Added content: ' . $post_id );

				return new \WP_REST_Response( $data, 200 );
			} catch ( \Throwable $th ) {
				// Handle error.
				$data['error'] = 'Adding content failed: ' . $th->getMessage();

				$this->log_debug( 'Error while adding content: ' . $th->getMessage() );

				return new \WP_REST_Response( $data, 400 );
			}
		}


		/**
		 * Publish post
		 *
		 * @param  \WP_REST_Request $request API request.
		 * @return \WP_REST_Response
		 * @throws \Exception Error if fails post publish.
		 */
		public function callback_publish_article( \WP_REST_Request $request ) {
			$params  = $request->get_json_params();
			$post_id = $params['post_id'];

			$this->log_debug( 'Publish post with params: ' . json_encode( $params ) );

			// Check if the post exists.
			$post = get_post( $post_id );
			if ( ! $post || 'post' !== $post->post_type ) {
				return new \WP_REST_Response( array( 'error' => 'Post not found.' ), 404 );
			}

			try {
				// Publish the post by removing the scheduled date.
				$id = wp_update_post(
					array(
						'ID'            => $post_id,
						'post_status'   => 'publish',
						'post_date'     => null,
						'post_date_gmt' => null,
					),
					true
				);

				if ( is_wp_error( $id ) ) {
					throw new \Exception( 'Post publish failed: ' . $post_id->get_error_message() );
				}

				// Update the post meta for boostsite.
				update_post_meta( $post_id, 'wp_autopost_ai_post_status', 'published' );

				$this->log_debug( 'Published post: ' . $post_id );

				return new \WP_REST_Response( array( 'id' => $id ), 200 );
			} catch ( \Throwable $th ) {
				$this->log_debug( 'Error while publishing post: ' . $th->getMessage() );

				// Handle error.
				return new \WP_REST_Response( array( 'error' => 'Post publish failed: ' . $th->getMessage() ), 400 );
			}
		}

			/**
	 * Authenticate
	 *
	 * @return mixed
	 */
	public function authenticate() {
		// Get Authorization header.
		$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? null;

		if ( empty( $auth_header ) ) {
			return new \WP_Error( 'rest_forbidden', __( 'Authorization header is missing.', 'boostsite-ai-content-generator' ), array( 'status' => 400 ) );
		}

		// Check if it's a Bearer token.
		if ( ! preg_match( '/^Bearer\s+(.+)$/i', $auth_header, $matches ) ) {
			return new \WP_Error( 'rest_forbidden', __( 'Invalid authorization format. Expected Bearer token.', 'boostsite-ai-content-generator' ), array( 'status' => 400 ) );
		}

		$provided_api_key = sanitize_text_field( $matches[1] );

		if ( empty( $provided_api_key ) ) {
			return new \WP_Error( 'rest_forbidden', __( 'API key is missing.', 'boostsite-ai-content-generator' ), array( 'status' => 400 ) );
		}

		// Get stored API key.
		$stored_api_key = $this->settings->get_single_setting( 'api_key' );

		if ( $provided_api_key !== $stored_api_key ) {
			return new \WP_Error( 'rest_forbidden', __( 'Invalid API key.', 'boostsite-ai-content-generator' ), array( 'status' => 403 ) );
		}

		$this->log_debug( '[REST API] Authenticated with API key' );

		// Authentication correct.
		return true;
	}

		/**
		 * Validate a string parameter.
		 *
		 * @param  mixed $param The parameter.
		 * @param  mixed $request The request.
		 * @param  mixed $key The key.
		 * @return boolean
		 */
		public function is_string_validation( $param, $request, $key ) {
			return is_string( $param );
		}

		/**
		 * Log debug messages.
		 *
		 * @param string $message Log message.
		 */
		private function log_debug( $message ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG && defined( 'BOOSTSITE_DEBUG' ) && BOOSTSITE_DEBUG ) {
				error_log( '[REST API Debug] ' . $message );
			}
		}
	}
}
