<?php

/********************************************************************
 * Copyright (C) 2025 Upvimeo.com (https://upvimeo.com)
 *
 * This file is part of Upvimeo
 *
 * Upvimeo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * Upvimeo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Upvimeo. If not, see <https://www.gnu.org/licenses/>.
 **********************************************************************/

use Vimeify\Vimeo\Exceptions\VimeoRequestException;

/**
 * Class UpVimeo_Ajax_Handler
 *
 * Responsible for ajax handling
 *
 * @license GPLv2
 * @copyright Upvimeo.com (https://upvimeo.com)
 * @since 1.0.0
 */
class UpVimeo_Ajax_Handler
{
	/**
	 * The settings api
	 * @var UpVimeo_Settings_Helper
	 */
	protected $settings_helper;

	/**
	 * The api helper
	 * @var UpVimeo_Api_Helper
	 */
	protected $api_helper;

	/**
	 * The database helper
	 * @var UpVimeo_Db_Helper
	 */
	protected $db_helper;

	/**
	 * The logger
	 * @var UpVimeo_Logger
	 */
	protected $logger;

	/**
	 * UpVimeo_Ajax_Handler constructor.
	 *
	 * @param $plugin_name
	 * @param $plugin_version
	 */
	public function __construct($plugin_name, $plugin_version)
	{
		$this->api_helper = new UpVimeo_Api_Helper();
		$this->db_helper = new UpVimeo_Db_Helper();
		$this->settings_helper = new UpVimeo_Settings_Helper();
		$this->logger = new UpVimeo_Logger();
	}

	/**
	 * Handles settings storage
	 */
	public function handle_settings()
	{
		if (!current_user_can(apply_filters('UPVIMEO_manage_options_capability', 'manage_options'))) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// Handle Cache Purge
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if (isset($_REQUEST['cv_purge_caches'])) {
			UpVimeo_Api_Helper::flush_cache();
			// Also clear transient caches
			global $wpdb;
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query($wpdb->prepare("DELETE FROM $wpdb->options WHERE option_name LIKE %s", '_transient_upvimeo_fsearch_%'));
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query($wpdb->prepare("DELETE FROM $wpdb->options WHERE option_name LIKE %s", '_transient_timeout_upvimeo_fsearch_%'));

			wp_send_json_success(array(
				'message' => __('Cache purged successfully.', 'upvimeo-direct-uploads'),
			));
			exit;
		}

		$fields = array(
			'upvimeo_client_id' => __('Client ID', 'upvimeo-direct-uploads'),
			'upvimeo_client_secret' => __('Client Secret', 'upvimeo-direct-uploads'),
			'upvimeo_access_token' => __('Access Token', 'upvimeo-direct-uploads'),
			'upvimeo_embed_domains' => __('Embed Domains', 'upvimeo-direct-uploads'),
			'upvimeo_view_privacy' => __('View Privacy for Admin Uploads', 'upvimeo-direct-uploads'),
			'upvimeo_mce_enable_account_search' => __('Enable Vimeo account search option in TinyMCE upload form', 'upvimeo-direct-uploads'),
			'upvimeo_gtb_enable_account_search' => __('Enable Vimeo account search option in Gutenberg upload form', 'upvimeo-direct-uploads'),
			'upvimeo_mce_enable_local_search' => __('Enable local library search option in TinyMCE upload form', 'upvimeo-direct-uploads'),
			'upvimeo_local_current_user_only' => __('Show only the Videos uploaded by the current user when using the local library option', 'upvimeo-direct-uploads'),
			'upvimeo_author_uploads_only' => __('Show Author uploads only', 'upvimeo-direct-uploads'),
			'upvimeo_enable_single_pages' => __('Single Video Pages', 'upvimeo-direct-uploads'),
			'upvimeo_exp_thumbs_support' => __('Experimental thumbnail support', 'upvimeo-direct-uploads'),
			'upvimeo_upload_folder' => __('Upload folder for WordPress admin uploads', 'upvimeo-direct-uploads'),
			'upvimeo_embed_preset' => __('Embed Preset for WordPress admin uploads', 'upvimeo-direct-uploads'),
			'upvimeo_enable_privacy_option_gt' => __('Enable Vimeo privacy dropdown in Gutenberg', 'upvimeo-direct-uploads'),
			'upvimeo_enable_privacy_option_mce' => __('Enable Vimeo privacy dropdown in TinyMCE', 'upvimeo-direct-uploads'),
			'upvimeo_enable_privacy_option_media' => __('Enable Vimeo privacy dropdown in Media screens', 'upvimeo-direct-uploads'),
			'upvimeo_enable_embed_presets_management' => __('Enable Embed Presets management in single edit page', 'upvimeo-direct-uploads'),
			'upvimeo_enable_embed_privacy_management' => __('Enable Embed Privacy management in single edit page', 'upvimeo-direct-uploads'),
			'upvimeo_enable_folders_management' => __('Enable Folders management in single edit page', 'upvimeo-direct-uploads'),
			'upvimeo_tutor_force_vimeo_only' => __('Force Vimeo-Only Mode for Tutor LMS', 'upvimeo-direct-uploads'),
		);

		$skip_delete = array('upvimeo_embed_preset');

		if ( file_exists( UPVIMEO_PATH . 'includes/pro/ajax-fields.php' ) ) {
			include UPVIMEO_PATH . 'includes/pro/ajax-fields.php';
		}

		$enable_single_pages = $this->settings_helper->get('upvimeo_enable_single_pages');

		// validate
		$required = array('upvimeo_client_id', 'upvimeo_client_secret', 'upvimeo_access_token');
		foreach ($fields as $key => $field) {
			if (in_array($key, $required)) {
				// phpcs:ignore WordPress.Security.NonceVerification.Missing
				if (!isset($_POST[$key]) || empty(sanitize_text_field(wp_unslash($_POST[$key]))) || empty(trim(sanitize_text_field(wp_unslash($_POST[$key]))))) {
					wp_send_json_error(array(
						/* translators: %s: field name */
						'message' => sprintf(__('Error: %s is required.', 'upvimeo-direct-uploads'), $field)
					));
					exit;
				}
			}
		}

		// save
		foreach ($fields as $key => $field) {
			// phpcs:ignore WordPress.Security.NonceVerification.Missing
			if (!isset($_POST[$key])) {
				if (in_array($key, $skip_delete)) {
					// In case user is switched to FREE subscription,
					// but later wants to extend it's subscription with >= PRO again. Keep this setting.
					continue;
				}
				$this->settings_helper->remove($key);
			} else {
				// phpcs:ignore WordPress.Security.NonceVerification.Missing
				$clean_value = sanitize_text_field(wp_unslash($_POST[$key]));
				$option_value = $this->prepare_setting($key, $clean_value);
				$this->settings_helper->set($key, $option_value);
			}
		}

		// flush permalinks
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$posted_enable_single_pages = isset($_POST['upvimeo_enable_single_pages']) ? sanitize_text_field(wp_unslash($_POST['upvimeo_enable_single_pages'])) : '';
		if ($enable_single_pages !== $posted_enable_single_pages) {
			flush_rewrite_rules(true);
		}

		// Save
		$this->settings_helper->save();

		// Re-render the api details
		UpVimeo_Api_Helper::flush_cache();
		$this->api_helper = new UpVimeo_Api_Helper();
		$api_info = upvimeo_get_view('admin/partials/api', array(
			'upvimeo_helper' => $this->api_helper
		));

		wp_send_json_success(array(
			'message' => __('Settings saved successfully!', 'upvimeo-direct-uploads'),
			'api_info' => $api_info,
		));
	}

	/**
	 * Prepare
	 *
	 * @param $key
	 * @param $value
	 *
	 * @return array|string
	 */
	public function prepare_setting($key, $value)
	{
		if ($key === 'upvimeo_embed_domains') {
			$domains = explode(',', $value);
			$clean_domains = array();
			foreach ($domains as $domain) {
				$domain = trim($domain);
				foreach (array('https://', 'http://', 'www.') as $part) {
					$domain = str_replace($part, '', $domain);
				}
				if (!empty($domain)) {
					$clean_domains[] = $domain;
				}
			}
			$value = implode(',', $clean_domains);
		}
		return $value;
	}

	/**
	 * Store upload on the server
	 */
	public function store_upload()
	{
		$logtag = 'upvimeo-EDITOR-UPLOAD';if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action. User must be Author, Editor or Administrator to edit.', 'upvimeo-direct-uploads')
			));
			exit;
		}
		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_post()) {
			wp_send_json_error(array(
				'message' => __('Invalid request.', 'upvimeo-direct-uploads'),
			));
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$title = isset($_POST['title']) ? sanitize_text_field(wp_unslash($_POST['title'])) : __('Untitled', 'upvimeo-direct-uploads');
		$description = isset($_POST['description']) ? sanitize_text_field(wp_unslash($_POST['description'])) : '';
		$size = isset($_POST['size']) ? intval(wp_unslash($_POST['size'])) : false;
		$meta_raw = isset($_POST['meta']) ? map_deep(wp_unslash($_POST['meta']), 'sanitize_text_field') : null;
		$uri = isset($_POST['uri']) ? sanitize_text_field(wp_unslash($_POST['uri'])) : '';
		// phpcs:enable
		$video_id = upvimeo_uri_to_id($uri);

		$meta = null;
		if (is_string($meta_raw)) {
			$decoded = json_decode($meta_raw, true);
			if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
				$decoded = map_deep($decoded, 'sanitize_text_field');
				$meta = $decoded;
			}
		}

		/**
		 * Upload success hook
		 */
		do_action('UPVIMEO_backend_after_upload', array(
			'upvimeo_title' => $title,
			'upvimeo_description' => $description,
			'upvimeo_id' => $video_id,
			'upvimeo_size' => $size,
			'upvimeo_meta' => $meta,
			'source' => array(
				'software' => 'Editor',
			),
		));

		$this->logger->log(sprintf('Video %s stored.', $uri), $logtag);

		wp_send_json_success(array(
			'message' => __('Video uploaded successfully.', 'upvimeo-direct-uploads'),
		));
		exit;
	}

	/**
	 * Handles video deletion
	 */
	public function handle_delete()
	{
		$logtag = 'upvimeo-ADMIN-EDIT';$required_cap = apply_filters('UPVIMEO_vimeo_cap_delete', 'delete_posts');

		if (!current_user_can($required_cap)) {
			wp_send_json_error(array(
				'title' => __('Permission denied', 'upvimeo-direct-uploads'),
				'message' => __('Your WordPress account doesn\'t have the required permissions do delete video.', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->api_helper->can_delete()) {
			wp_send_json_error(array(
				'title' => __('Permission denied', 'upvimeo-direct-uploads'),
				'message' => __('Your vimeo account doesn\'t have the delete scope to perform this action.', 'upvimeo-direct-uploads')
			));
			exit;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$posted_vimeo_uri = isset($_POST['upvimeo_uri']) ? sanitize_text_field(wp_unslash($_POST['upvimeo_uri'])) : '';
		$posted_post_id = isset($_POST['post_id']) && is_numeric($_POST['post_id']) ? intval(wp_unslash($_POST['post_id'])) : null;
		// phpcs:enable

		if (empty($posted_vimeo_uri)) {

			$args = array(
				'title' => __('Missing video', 'upvimeo-direct-uploads'),
				'message' => __('Select valid vimeo video to delete.', 'upvimeo-direct-uploads')
			);

			if (!is_null($posted_post_id)) {
				$post_id_to_delete = $posted_post_id;
				if (!current_user_can('delete_post', $post_id_to_delete)) {
					wp_send_json_error(array(
						'title' => __('Permission denied', 'upvimeo-direct-uploads'),
						'message' => __('You do not have permission to delete this video.', 'upvimeo-direct-uploads')
					));
					exit;
				}
				$deleted = wp_delete_post($post_id_to_delete, 1);
				if ($deleted) {
					$args['title'] = __('Success', 'upvimeo-direct-uploads');
					$args['message'] = __('Video deleted successfully.', 'upvimeo-direct-uploads');
					$args['local_delete'] = 1;
					wp_send_json_success($args);
					exit;
				}
			}
			wp_send_json_error($args);
			exit;
		}

		$vimeo_uri = upvimeo_id_to_uri($posted_vimeo_uri);
		$vimeo_post_id = $this->db_helper->get_post_id($vimeo_uri);
		$vimeo_post_exists = (false !== get_post_status($vimeo_post_id));

		try {
			$response = $this->api_helper->delete($vimeo_uri);
			if ($response['status'] !== 204 && (isset($response['body']['error']) && !empty($response['body']['error']))) {
				$local_delete = false;
				if ($vimeo_post_exists) {
					if (!current_user_can('delete_post', $vimeo_post_id)) {
						wp_send_json_error(array(
							'title' => __('Permission denied', 'upvimeo-direct-uploads'),
							'message' => __('You do not have permission to delete this video.', 'upvimeo-direct-uploads')
						));
						exit;
					}
					$local_delete = true;
					wp_delete_post($vimeo_post_id, true);
					$this->logger->log(sprintf('Local video %s deleted', $vimeo_post_id), $logtag);
				}
				$this->logger->log(sprintf('Unable to delete remote video %s', $vimeo_uri), $logtag);
				wp_send_json_error(array(
					'title' => __('Sorry!', 'upvimeo-direct-uploads'),
					'message' => isset($response['body']['error']) ? sanitize_text_field($response['body']['error']) : __('Unknown Error', 'upvimeo-direct-uploads'),
					'local_delete' => $local_delete,
				));
			} elseif ($response['status'] === 204) {
				$local_delete = false;
				if ($vimeo_post_exists) {
					if (!current_user_can('delete_post', $vimeo_post_id)) {
						// Remote video already deleted, but we can't delete local?
						// This state is tricky. User had rights to delete remote (via API check earlier? No, API check is generic access token).
						// But if valid WP post, we must enforce WP perms.
						// If we fail here, we return success for remote delete but fail local?
						// Let's enforce it.
						wp_send_json_error(array(
							'title' => __('Permission denied', 'upvimeo-direct-uploads'),
							'message' => __('Video deleted from Vimeo, but you do not have permission to delete the local WordPress reference.', 'upvimeo-direct-uploads')
						));
						exit;
					}
					$local_delete = true;
					wp_delete_post($vimeo_post_id, true);
					$this->logger->log(sprintf('Local video %s deleted', $vimeo_post_id), $logtag);
				}
				$this->logger->log(sprintf('Remote video %s deleted', $vimeo_uri), $logtag);
				wp_send_json_success(array(
					'title' => __('Success', 'upvimeo-direct-uploads'),
					'message' => __('Video deleted successfully!', 'upvimeo-direct-uploads'),
					'local_delete' => $local_delete
				));
			} else {
				$this->logger->log(sprintf('Unable to delete remote video %s', $vimeo_uri), $logtag);
				wp_send_json_error(array(
					'title' => __('Sorry!', 'upvimeo-direct-uploads'),
					'message' => __('The video was not deleted.', 'upvimeo-direct-uploads')
				));
			}
		} catch (\Exception $e) {
			$this->logger->log(sprintf('Unable to delete remote video %s. Local %s video deleted. Error: %s', $vimeo_uri, $vimeo_post_id, $e->getMessage()), $logtag);
			wp_delete_post($vimeo_post_id, true);
			wp_send_json_success(array(
				'title' => __('Success', 'upvimeo-direct-uploads'),
				'message' => __('Video deleted successfully. However we had a trouble deleting the vimeo from vimeo.com. It may be deleted or belongs to different account.', 'upvimeo-direct-uploads'),
				'local_delete' => true,
			));
			exit;
		}
	}

	/**
	 * Handle basic edit vimeo
	 */
	public function handle_basic_edit()
	{
		$logtag = 'upvimeo-ADMIN-EDIT';if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_post()) {
			wp_send_json_error(array(
				'message' => __('Invalid request', 'upvimeo-direct-uploads')
			));
			exit;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$uri = isset($_POST['uri']) ? sanitize_text_field(wp_unslash($_POST['uri'])) : '';
		$name = isset($_POST['name']) ? sanitize_text_field(wp_unslash($_POST['name'])) : null;
		$description = isset($_POST['description']) ? sanitize_textarea_field(wp_unslash($_POST['description'])) : null;
		$view_privacy = isset($_POST['view_privacy']) ? sanitize_key(wp_unslash($_POST['view_privacy'])) : null;

		if (isset($_POST['name']) && empty($name)) {
			// phpcs:enable
			wp_send_json_error(array(
				'message' => __('Please enter valid name', 'upvimeo-direct-uploads')
			));
			exit;
		}

		try {
			/**
			 * Basic details
			 */
			$params = array();

			if (!is_null($name)) {
				$params['name'] = $name;
			}
			if (!is_null($description)) {
				$params['description'] = $description;
			}

			/**
			 * Set privacy
			 */
			if (!is_null($view_privacy)) {
				$privacy = $this->get_view_privacy($view_privacy);
				if (!empty($privacy)) {
					if ('default' !== $privacy) {
						$params['privacy'] = array('view' => $privacy);
					}
				}
			}

			if (empty($params)) {
				wp_send_json_error(array(
					'message' => __('Nothing to update', 'upvimeo-direct-uploads')
				));
				exit;
			}
			/**
			 * Update video
			 */
			$post_ID = $this->db_helper->get_post_id($uri);

			// Check if user can edit this post if it exists locally
			if ($post_ID && !current_user_can('edit_post', $post_ID)) {
				wp_send_json_error(array(
					'message' => __('You do not have permission to edit this video.', 'upvimeo-direct-uploads')
				));
				exit;
			}

			$response = $this->api_helper->edit($uri, $params);

			/**
			 * Respond back
			 */
			if (isset($response['status'])) {
				if ($response['status'] === 200) {
					if (!is_null($name) && $post_ID) {
						if (current_user_can('edit_post', $post_ID)) {
							wp_update_post(array(
								'ID' => $post_ID,
								'post_title' => $name,
							));
						} else {
							$this->logger->log(sprintf('User tried to update title for video %s but lacks edit_post capability', $uri), $logtag);
						}
					}
					$this->logger->log(sprintf('Video "%s" saved', $uri), $logtag);
					wp_send_json_success(array(
						'message' => __('Video saved successfully', 'upvimeo-direct-uploads')
					));
				} else {
					$error_msg = isset($response['body']['error']) ? sanitize_text_field($response['body']['error']) : 'Unknown Error';
					$this->logger->log(sprintf('Unable to save video %s. Error: %s', $uri, $error_msg), $logtag);
					wp_send_json_error(array(
						'message' => __('Error saving the video: ', 'upvimeo-direct-uploads') . $error_msg
					));
				}
			} else {
				$this->logger->log(sprintf('Unable to save video %s', $uri), $logtag);
				wp_send_json_error(array(
					'message' => __('Unknown error.', 'upvimeo-direct-uploads'),
				));
			}
		} catch (VimeoRequestException $e) {

			$this->logger->log(sprintf('Unable to save video  %s', $uri), $logtag);

			wp_send_json_error(array(
				'message' => $e->getMessage(),
			));
		}
		exit;
	}

	/**
	 * Handle embed privacy
	 */
	public function handle_embed_privacy()
	{
		$logtag = 'upvimeo-ADMIN-EDIT';if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_post()) {
			wp_send_json_error(array(
				'message' => __('Invalid request', 'upvimeo-direct-uploads')
			));
			exit;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$uri = isset($_POST['uri']) ? sanitize_text_field(wp_unslash($_POST['uri'])) : '';

		$privacy_embed = isset($_POST['privacy_embed']) ? sanitize_text_field(wp_unslash($_POST['privacy_embed'])) : '';
		// phpcs:enable

		if (empty($privacy_embed) || !in_array($privacy_embed, array('public', 'whitelist'))) {
			wp_send_json_error(array(
				'message' => __('Invalid embed privacy mehtod.', 'upvimeo-direct-uploads'),
			));
			exit;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$whitelist_domain = isset($_POST['privacy_embed_domain']) ? sanitize_text_field(wp_unslash($_POST['privacy_embed_domain'])) : '';

		try {
			$this->api_helper->set_embed_privacy($uri, $privacy_embed);
			if ('whitelist' === $privacy_embed && !empty($whitelist_domain)) {
				if (!upvimeo_is_valid_domain_name($whitelist_domain)) {
					$this->logger->log(sprintf('Unable to whitelist domain %s for %s. Error: Invalid format', $whitelist_domain, $uri), $logtag);
					wp_send_json_error(array(
						'message' => __('Invalid domain. Please enter valid domain name.', 'upvimeo-direct-uploads'),
					));
					exit;
				} else {
					$whitelist_response = $this->api_helper->whitelist_domain_add($uri, $whitelist_domain);
					$this->logger->log(sprintf('Domain %s added to whitelist for %s', $whitelist_domain, $uri), $logtag);
					if (isset($whitelist_response['status'])) {
						if ($whitelist_response['status'] >= 200 && $whitelist_response['status'] < 300) {
							wp_send_json_success(array(
								'message' => __('Domain added to embed whitelist.', 'upvimeo-direct-uploads'),
								'domain_added' => $whitelist_domain,
								'uri' => $uri,
							));
							exit;
						} else {
							wp_send_json_error(array(
								'message' => __('Failed to add domain to the embed whitelist.', 'upvimeo-direct-uploads'),
							));
							exit;
						}
					} else {
						wp_send_json_error(array(
							'message' => __('Invalid response received from vimeo', 'upvimeo-direct-uploads')
						));
						exit;
					}
				}
			} else {
				wp_send_json_success(array(
					'message' => __('Embed privacy changed successfully.', 'upvimeo-direct-uploads'),
				));
				exit;
			}
		} catch (\Exception $e) {
			if ('whitelist' === $privacy_embed) {
				/* translators: 1: domain name, 2: video uri, 3: error message */
				$message = sprintf(__('Unable to whitelist domain %1$s for %2$s. Error: %3$s', 'upvimeo-direct-uploads'), $whitelist_domain, $uri, $e->getMessage());
			} else {
				/* translators: 1: video uri, 2: error message */
				$message = sprintf(__('Unable to change embed privacy for %1$s. Error: %2$s', 'upvimeo-direct-uploads'), $uri, $e->getMessage());
			}
			wp_send_json_error(array(
				'message' => $message,
			));
			exit;
		}
	}

	/**
	 * Handles whitelist removal
	 */
	public function handle_embed_privacy_whitelist_remove()
	{
		$logtag = 'upvimeo-ADMIN-EDIT';if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_post()) {
			wp_send_json_error(array(
				'message' => __('Invalid request', 'upvimeo-direct-uploads')
			));
			exit;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$uri = isset($_POST['uri']) ? sanitize_text_field(wp_unslash($_POST['uri'])) : '';

		if (empty($uri)) {
			wp_send_json_error(array(
				'message' => __('Invalid video URI specified', 'upvimeo-direct-uploads')
			));
			exit;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$whitelist_domain = isset($_POST['domain']) ? sanitize_text_field(wp_unslash($_POST['domain'])) : '';

		try {
			$whitelist_response = $this->api_helper->whitelist_domain_remove($uri, $whitelist_domain);
			$this->logger->log(sprintf('Domain %s whitelisted for %s', $whitelist_domain, $uri), $logtag);
		} catch (VimeoRequestException $e) {
			$this->logger->log(sprintf('Error removing domain from whitelist (%s)', $e->getMessage()), $logtag);
			wp_send_json_success(array(
				'message' => __('Error removing domain from whitelist.', 'upvimeo-direct-uploads'),
			));
			exit;
		}
		if (isset($whitelist_response['status'])) {
			if ($whitelist_response['status'] === 204) {
				wp_send_json_success(array(
					'message' => __('Domain removed successfully', 'upvimeo-direct-uploads'),
				));
			} else {
				wp_send_json_error(array(
					'message' => isset($whitelist_response['body']['error']) ? sanitize_text_field($whitelist_response['body']['error']) : __('Failed to remove domain from embed privacy whitelist.', 'upvimeo-direct-uploads')
				));
				exit;
			}
		} else {
			wp_send_json_error(array(
				'message' => __('Invalid response received from vimeo', 'upvimeo-direct-uploads')
			));
			exit;
		}
	}

	/**
	 * Handles Video folder update. Remove or add video to folder.
	 */
	public function handle_video_folder_set()
	{
		$logtag = 'upvimeo-ADMIN-EDIT';if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$video_uri = isset($_POST['video_uri']) ? sanitize_text_field(wp_unslash($_POST['video_uri'])) : null;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$folder_uri = isset($_POST['folder_uri']) ? sanitize_text_field(wp_unslash($_POST['folder_uri'])) : null;
		$video_id = upvimeo_uri_to_id($video_uri);

		if (empty($video_uri)) {
			wp_send_json_error(array(
				'message' => __('Video missing.', 'upvimeo-direct-uploads'),
			));
			exit;
		}
		if (empty($folder_uri)) {
			wp_send_json_error(array(
				'message' => __('Folder missing.', 'upvimeo-direct-uploads'),
			));
			exit;
		}

		// Handle default
		if ($folder_uri === 'default') {
			$video = $this->api_helper->get('/videos/' . $video_id . '?fields=parent_folder');
			$folder_uri = isset($video['body']['parent_folder']['uri']) && !empty($video['body']['parent_folder']['uri']) ? $video['body']['parent_folder']['uri'] : null;
			if ($folder_uri) {
				try {
					$response = $this->api_helper->remove_video_folder($video_uri, $folder_uri);
					$this->logger->log(sprintf('Folder changed to %s for %s', 'default', $video_uri), $logtag);
					if (isset($response['status'])) {
						if (in_array($response['status'], array(200, 204))) {
							$this->logger->log(sprintf('Folder changed to %s for %s', 'default', $video_uri), $logtag);
							wp_send_json_success(array(
								'message' => __('Video removed from folder successfully.', 'upvimeo-direct-uploads'),
							));
						} else {
							$error = '';
							if (isset($response['body']['error'])) {
								$error = sprintf('Error: %s', $response['body']['error']);
							}
							$this->logger->log(sprintf('Unable to change folder to %s for %s. %s', 'default', $video_uri, $error), $logtag);
							wp_send_json_success(array(
								/* translators: %s: [description of variable] */
								'message' => sprintf(__('Unable to change folder. %s', 'upvimeo-direct-uploads'), $error),
							));
						}
					} else {
						$this->logger->log(sprintf('Unable to set folder %s for %s. Error: Unreadable response', 'default', $video_uri), $logtag);
						wp_send_json_error(array(
							'message' => __('Invalid response received from vimeo', 'upvimeo-direct-uploads'),
						));
					}
				} catch (VimeoRequestException $e) {
					$this->logger->log(sprintf('Unable to remove folder %s for %s. Error: %s', $folder_uri, $video_uri, $e->getMessage()), $logtag);
					wp_send_json_error(array(
						'message' => $e->getMessage(),
					));
				}
			} else {
				$this->logger->log(sprintf('Unable to set folder %s for %s. Error: Invalid folder', $folder_uri, $video_uri), $logtag);
				wp_send_json_error(array(
					'message' => __('Unexpected error! Sorry.', 'upvimeo-direct-uploads'),
				));
			}
		} else { // Handle folder
			try {
				$response = $this->api_helper->set_video_folder($video_uri, $folder_uri);
				if (isset($response['status'])) {
					if (in_array($response['status'], array(200, 204))) {
						$this->logger->log(sprintf('Folder changed to %s for %s', $folder_uri, $video_uri), $logtag);
						wp_send_json_success(array(
							'message' => __('Video moved to folder successfully.', 'upvimeo-direct-uploads'),
						));
					} else {
						$error = '';
						if (isset($response['body']['error'])) {
							$error = sprintf('Error: %s', $response['body']['error']);
						}
						$this->logger->log(sprintf('Unable to change folder to %s for %s. %s', $folder_uri, $video_uri, $error), $logtag);
						wp_send_json_success(array(
							/* translators: %s: [description of variable] */
							'message' => sprintf(__('Unable to change folder. %s', 'upvimeo-direct-uploads'), $error),
						));
					}
				} else {
					$this->logger->log(sprintf('Unable to set folder %s for %s. Error: Unreadable response', $folder_uri, $video_uri), $logtag);
					wp_send_json_error(array(
						'message' => __('Invalid response received from vimeo', 'upvimeo-direct-uploads'),
					));
				}
			} catch (VimeoRequestException $e) {
				$this->logger->log(sprintf('Unable to set folder %s for %s. Error: %s', $folder_uri, $video_uri, $e->getMessage()), $logtag);
				wp_send_json_error(array(
					'message' => $e->getMessage(),
				));
			}
		}
		exit;
	}

	/**
	 * Import video from Vimeo to WordPress
	 */
	public function handle_import_video()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action.', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$vimeo_id = isset($_POST['upvimeo_id']) ? sanitize_text_field(wp_unslash($_POST['upvimeo_id'])) : '';
		$vimeo_uri = isset($_POST['upvimeo_uri']) ? sanitize_text_field(wp_unslash($_POST['upvimeo_uri'])) : '';
		$title = isset($_POST['title']) ? sanitize_text_field(wp_unslash($_POST['title'])) : '';
		$description = isset($_POST['description']) ? sanitize_textarea_field(wp_unslash($_POST['description'])) : '';
		// phpcs:enable

		if (empty($vimeo_id)) {
			wp_send_json_error(array('message' => __('Invalid Vimeo ID', 'upvimeo-direct-uploads')));
			exit;
		}

		$post_id = $this->db_helper->create_local_video($title, $description, $vimeo_id, 'manual_import');

		if (!is_wp_error($post_id)) {
			// Update additional meta
			// phpcs:disable WordPress.Security.NonceVerification.Missing
			if (isset($_POST['duration']))
				update_post_meta($post_id, 'UPVIMEO_duration', intval(wp_unslash($_POST['duration'])));
			if (isset($_POST['width']))
				update_post_meta($post_id, 'UPVIMEO_width', intval(wp_unslash($_POST['width'])));
			if (isset($_POST['height']))
				update_post_meta($post_id, 'UPVIMEO_height', intval(wp_unslash($_POST['height'])));
			// phpcs:enable

			// Link
			$vimeo_link = sprintf('https://vimeo.com/%s', $vimeo_id);
			update_post_meta($post_id, 'UPVIMEO_link', $vimeo_link);

			wp_send_json_success(array(
				'message' => __('Video imported successfully.', 'upvimeo-direct-uploads'),
				'id' => $post_id
			));
		} else {
			wp_send_json_error(array(
				'message' => $post_id->get_error_message()
			));
		}
		exit;
	}

	/**
	 * Handles Video embed preset update. Remove or add embed preset to video.
	 */
	public function handle_video_embed_preset_set()
	{
		$logtag = 'upvimeo-ADMIN-EDIT';
		if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}
		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$video_uri = isset($_POST['video_uri']) ? sanitize_text_field(wp_unslash($_POST['video_uri'])) : null;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$preset_uri = isset($_POST['embed_preset_uri']) ? sanitize_text_field(wp_unslash($_POST['embed_preset_uri'])) : null;
		$video_id = upvimeo_uri_to_id($video_uri);

		if (empty($video_uri)) {
			wp_send_json_error(array(
				'message' => __('Video missing.', 'upvimeo-direct-uploads'),
			));
			exit;
		}
		if (empty($preset_uri)) {
			wp_send_json_error(array(
				'message' => __('Preset missing.', 'upvimeo-direct-uploads'),
			));
			exit;
		}

		// Handle default
		if ($preset_uri === 'default') {
			$video = $this->api_helper->get('/videos/' . $video_id . '?fields=embed');
			$preset_uri = isset($video['body']['embed']['uri']) && !empty($video['body']['embed']['uri']) ? $video['body']['embed']['uri'] : null;
			if ($preset_uri) {
				try {
					$response = $this->api_helper->remove_video_embed_preset($video_uri, $preset_uri);
					if (isset($response['status'])) {
						if (in_array($response['status'], array(200, 204))) {
							$this->logger->log(sprintf('Embed preset removed: %s from %s', $preset_uri, $video_uri), $logtag);
							wp_send_json_success(array(
								'message' => __('Embed preset removed from Video successfully.', 'upvimeo-direct-uploads'),
							));
						} else {
							$error = '';
							if (isset($response['body']['error'])) {
								$error = sprintf('Error: %s', $response['body']['error']);
							}
							$this->logger->log(sprintf('Unable to remove embed preset %s from %s. %s', $preset_uri, $video_uri, $error), $logtag);
							wp_send_json_success(array(
								/* translators: %s: [description of variable] */
								'message' => sprintf(__('Unable to remove embed preset. %s', 'upvimeo-direct-uploads'), $error),
							));
						}
					} else {
						$this->logger->log(sprintf('Unable to remove embed preset %s from %s. Error: Unreadable response', $preset_uri, $video_uri), $logtag);
						wp_send_json_error(array(
							'message' => __('Invalid response received from vimeo', 'upvimeo-direct-uploads'),
						));
					}
				} catch (VimeoRequestException $e) {
					$this->logger->log(sprintf('Unable to remove embed preset %s from %s. Error: %s', $preset_uri, $video_uri, $e->getMessage()), $logtag);
					wp_send_json_error(array(
						'message' => $e->getMessage(),
					));
				}
			}
		} else {
			try {
				$response = $this->api_helper->set_video_embed_preset($video_uri, $preset_uri);
				if (isset($response['status'])) {
					if (in_array($response['status'], array(200, 204))) {
						$this->logger->log(sprintf('Embed preset changed to %s for %s', $preset_uri, $video_uri), $logtag);
						wp_send_json_success(array(
							'message' => __('Embed preset added to Video successfully.', 'upvimeo-direct-uploads'),
						));
					} else {
						$error = '';
						if (isset($response['body']['error'])) {
							$error = sprintf('Error: %s', $response['body']['error']);
						}
						$this->logger->log(sprintf('Unable to change embed preset to %s for %s. %s', $preset_uri, $video_uri, $error), $logtag);
						wp_send_json_success(array(
							/* translators: %s: [description of variable] */
							'message' => sprintf(__('Unable to change embed preset. %s', 'upvimeo-direct-uploads'), $error),
						));
					}
				} else {
					$this->logger->log(sprintf('Unable to set embed preset %s for %s. Error: Unreadable response', $preset_uri, $video_uri), $logtag);
					wp_send_json_error(array(
						'message' => __('Invalid response received from vimeo', 'upvimeo-direct-uploads'),
					));
				}
			} catch (VimeoRequestException $e) {
				$this->logger->log(sprintf('Unable to set embed preset %s for %s. Error: %s', $preset_uri, $video_uri, $e->getMessage()), $logtag);
				wp_send_json_error(array(
					'message' => $e->getMessage(),
				));
			}
		}
		exit;
	}
	/**
	 * Handles attachment upload
	 */
	public function handle_attachment2vimeo()
	{
		$logtag = 'upvimeo-ADMIN-A2V';
		if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_post()) {
			wp_send_json_error(array('message' => __('Invalid request', 'upvimeo-direct-uploads')));
			exit;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$ID = isset($_POST['attachment_id']) ? absint($_POST['attachment_id']) : 0;
		$raw_title = isset($_POST['upvimeo_title']) ? sanitize_text_field(wp_unslash($_POST['upvimeo_title'])) : '';
		$title = strlen(trim($raw_title)) > 0 ? $raw_title : null;
		$raw_desc = isset($_POST['upvimeo_description']) ? sanitize_textarea_field(wp_unslash($_POST['upvimeo_description'])) : '';
		$desc = strlen(trim($raw_desc)) > 0 ? $raw_desc : null;
		$view_priv = isset($_POST['upvimeo_view_privacy']) && !empty($_POST['upvimeo_view_privacy']) ? sanitize_text_field(wp_unslash($_POST['upvimeo_view_privacy'])) : null;
		// phpcs:enable

		if ($ID <= 0) {
			wp_send_json_error(array('message' => __('Invalid attachment', 'upvimeo-direct-uploads')));
			exit;
		}

		if (is_null($title)) {
			wp_send_json_error(array('message' => __('Please enter valid video title.', 'upvimeo-direct-uploads')));
			exit;
		}

		$file_path = get_attached_file($ID);
		$file_size = file_exists($file_path) ? filesize($file_path) : false;

		try {
			$params = array(
				'name' => $title,
			);

			if (!is_null($desc)) {
				$params['description'] = $desc;
			}

			/**
			 * Perform the upload
			 */
			$result = $this->api_helper->upload($file_path, $params);
			$vimeo_uri = $result['response'];
			$vimeo_id = upvimeo_uri_to_id($vimeo_uri);

			/**
			 * Upload success hook
			 */
			do_action('UPVIMEO_backend_after_upload', array(
				'upvimeo_title' => $title,
				'upvimeo_description' => $desc,
				'upvimeo_id' => $vimeo_id,
				'upvimeo_size' => $file_size,
				'overrides' => array(
					'view_privacy' => $view_priv,
				),
				'source' => array(
					'software' => 'Media Table',
					'media_id' => $ID,
				)
			));

			$this->logger->log(sprintf('Media library video #%s uploaded to Vimeo', $ID), $logtag);

			wp_send_json_success(array(
				'upvimeo_id' => $vimeo_id,
				'info_metabox_html' => upvimeo_render_media_library_upload_buttons($ID)
			));
		} catch (\Exception $e) {
			$this->logger->log(sprintf('Failed to uplaod from media library screen (%s)', $e->getMessage()), $logtag);
			/* translators: %s: [description of variable] */
			wp_send_json_error(sprintf(__('Upload failed: %s', 'upvimeo-direct-uploads'), $e->getMessage()));
		}
		exit;
	}
	/**
	 * Handles attachment delete
	 */
	public function handle_attachment2vimeo_delete()
	{
		$logtag = 'upvimeo-ADMIN-A2V';if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_post()) {
			wp_send_json_error(array('message' => __('Invalid request', 'upvimeo-direct-uploads')));
			exit;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$ID = isset($_POST['attachment_id']) ? absint($_POST['attachment_id']) : 0;

		if ($ID <= 0) {
			wp_send_json_error(array('message' => __('Invalid attachment', 'upvimeo-direct-uploads')));
			exit;
		}

		$meta = get_post_meta($ID, 'upvimeo', true);

		if (!isset($meta['upvimeo_id'])) {
			wp_send_json_error(array('message' => __('Invalid attachment', 'upvimeo-direct-uploads')));
			exit;
		} else {
			try {
				$uri = '/videos/' . $meta['upvimeo_id'];
				$response = $this->api_helper->delete($uri);
				$local_id = isset($meta['local_id']) ? (int) $meta['local_id'] : 0;
				if ($local_id > 0) {
					wp_delete_post($local_id, true);
				}
				delete_post_meta($ID, 'upvimeo');
				$this->logger->log(sprintf('Media library video %s deleted from Vimeo', $uri), $logtag);
				wp_send_json_success(array(
					'message' => __('Video deleted from vimeo successfully', 'upvimeo-direct-uploads'),
					'info_metabox_html' => upvimeo_render_media_library_upload_buttons($ID),
					'data' => $response,
				));
			} catch (\Exception $e) {
				$this->logger->log(sprintf('Unable to delete from media library screen (%s)', $e->getMessage()), $logtag);
				wp_send_json_error(array('message' => __('Invalid attachment', 'upvimeo-direct-uploads')));
				exit;
			}
		}
	}

	/**
	 * Return the uploaded videos
	 */
	public function get_uploads()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		if (!$this->is_http_get()) {
			wp_send_json_error(array(
				'message' => __('Invalid request', 'upvimeo-direct-uploads')
			));
			exit;
		}

		$current_user_uploads = !current_user_can('manage_options') && (int) $this->settings_helper->get('UPVIMEO_local_current_user_only');

		$uplaods = $this->db_helper->get_uploaded_videos($current_user_uploads);

		wp_send_json_success(array(
			'uploads' => $uplaods,
		));
		exit;
	}

	/**
	 * Handles user search
	 */
	public function handle_user_search()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		$items = array();
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$phrase = isset($_REQUEST['search_str']) ? sanitize_text_field(wp_unslash($_REQUEST['search_str'])) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page_num = isset($_REQUEST['page_number']) ? intval(wp_unslash($_REQUEST['page_number'])) : 1;
		$per_page = 25;

		$params = array(
			'number' => $per_page,
			'paged' => $page_num,
		);
		if (!empty($phrase)) {
			$params['search'] = '*' . esc_attr($phrase) . '*';
			$params['search_columns'] = array(
				'user_login',
				'user_nicename',
				'user_email',
				'user_url',
			);
		}
		$query = new \WP_User_Query($params);
		foreach ($query->get_results() as $user) {
			$items[] = array(
				'id' => $user->ID,
				'text' => sprintf('%s (#%d - %s)', $user->user_nicename, $user->ID, $user->user_email)
			);
		}

		wp_send_json_success([
			'results' => $items,
			'pagination' => [
				'more' => !empty($items)
			]
		]);
	}

	/**
	 * Handles folder search
	 * @return void
	 */
	public function handle_folder_search()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$phrase = isset($_REQUEST['search_str']) ? sanitize_text_field(wp_unslash($_REQUEST['search_str'])) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page_num = isset($_REQUEST['page_number']) ? intval(wp_unslash($_REQUEST['page_number'])) : 1;
		$per_page = 50; // Increased default per page for better UX

		// Caching Strategy
		$cache_key = 'upvimeo_fsearch_' . md5(get_current_user_id() . '_' . $phrase . '_' . $page_num);
		$folders_response = get_transient($cache_key);

		if (false === $folders_response) {
			$request = [
				'per_page' => $per_page,
				'page' => $page_num,
				'query' => $phrase
			];

			try {
				$folders_response = $this->api_helper->get_folders_query($request);
				// Cache for 10 minutes if successful
				if (!empty($folders_response)) {
					set_transient($cache_key, $folders_response, 600);
				}
			} catch (\Exception $e) {
			}
		}

		$data = !empty($folders_response['results']) ? $folders_response['results'] : [];
		$items = [
			[
				'id' => 'default',
				'text' => __('Default (no folder)', 'upvimeo-direct-uploads')
			]
		];
		foreach ($data as $entry) {
			$items[] = [
				'id' => $entry['uri'],
				'name' => $entry['name'],
				'text' => $entry['name'],
			];
		}

		wp_send_json_success([
			'results' => $items,
			'pagination' => [
				'more' => isset($folders_response['paging']['has_more']) ? $folders_response['paging']['has_more'] : false,
			]
		]);
	}

	/**
	 * Handles the statistics
	 * @return void
	 */
	public function handle_generate_stats()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		$params = [];

		$author_uplaods_only = (int) $this->settings_helper->get('UPVIMEO_author_uploads_only');

		if ($author_uplaods_only) {
			$params['author'] = get_current_user_id();
		}

		$total_uplaoded = $this->db_helper->get_total_uploaded_size($params);

		$view = upvimeo_get_view('admin/partials/library-stats', array(
			'total_uploaded' => upvimeo_format_bytes($total_uplaoded),
		));

		wp_send_json_success(['html' => $view]);
	}

	/**
	 * Obtian the privacy option based on input and plan support.
	 *
	 * @param $input
	 *
	 * @return mixed|string|null
	 *
	 * @since 1.7.0
	 */
	private function get_view_privacy($input)
	{
		$default = $this->settings_helper->get('UPVIMEO_view_privacy');
		$privacy = $input === 'default' || empty($input) ? $default : $input;
		if ($this->api_helper->supports_view_privacy_option($privacy)) {
			return $privacy;
		} else {
			return 'default';
		}
	}

	/**
	 * Utility function to check if the request is GET
	 * @return bool
	 */
	private function is_http_get()
	{
		$method = isset($_SERVER['REQUEST_METHOD']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) : '';
		return $method === 'GET';
	}

	/**
	 * Utility function to check if the request is POST
	 * @return bool
	 */
	private function is_http_post()
	{
		$method = isset($_SERVER['REQUEST_METHOD']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) : '';
		return $method === 'POST';
	}

	/**
	 * Utility function to chec kif the request is secure
	 *
	 * @param $nonce_name
	 *
	 * @return bool|int
	 */
	private function check_referer($nonce_name)
	{
		return check_ajax_referer($nonce_name, '_wpnonce', false);
	}

	/**
	 * Handle upload ticket generation
	 */
	public function handle_upload()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array(
				'message' => __('Unauthorized action', 'upvimeo-direct-uploads')
			));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$size = isset($_POST['size']) ? intval(wp_unslash($_POST['size'])) : 0;
		$name = isset($_POST['name']) ? sanitize_text_field(wp_unslash($_POST['name'])) : '';
		$description = isset($_POST['description']) ? sanitize_textarea_field(wp_unslash($_POST['description'])) : '';
		// phpcs:enable

		if ($size <= 0) {
			wp_send_json_error(array(
				'message' => __('Invalid file size.', 'upvimeo-direct-uploads')
			));
		}

		try {
			$ticket = $this->api_helper->create_upload_ticket($size, array(
				'name' => $name,
				'description' => $description
			));

			wp_send_json_success($ticket['body']);
		} catch (\Exception $e) {
			wp_send_json_error(array(
				'message' => $e->getMessage()
			));
		}
	}

	/**
	 * Fetch allowed domains from Vimeo
	 */
	public function handle_fetch_domains()
	{
		if (!current_user_can(apply_filters('UPVIMEO_manage_options_capability', 'manage_options'))) {
			wp_send_json_error(array('message' => __('Unauthorized action', 'upvimeo-direct-uploads')));
			exit;
		}
		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		try {
			$domains = $this->api_helper->get_whitelist_domains();

			// Clear caches
			delete_transient(UpVimeo_Api_Helper::CACHE_KEY_FOLDERS);
			delete_transient(UpVimeo_Api_Helper::CACHE_KEY_EMBED_PRESETS);

			$message = __('Domains fetched successfully.', 'upvimeo-direct-uploads');

			// Check if the result is empty.
			if (empty($domains)) {
				// We tried standard endpoint and discovery. If both failed/returned empty, check if we had a 404.
				// Based on previous debugging, "Plus" accounts often return 404 for this endpoint.
				// We should inform the user to use manual entry.

				// Quick check on the last request status if available
				$last_status = 200;
				if ($this->api_helper->api) {
					// We can't easily get the last status without re-requesting or storing it.
					// But we can check if the user is on a plan likely to fail.
					// For now, just append a helpful hint.
					$message = __('No domains returned. If you are on a "Plus" or "Basic" plan, this feature might not be supported via API. Please add your domains manually below.', 'upvimeo-direct-uploads');

					// Send as 'info' type result (success=true but with warning message)
					wp_send_json_success(array(
						'results' => [],
						'message' => $message,
						'type' => 'info' // Custom flag for frontend
					));
					return;
				}
			}

			wp_send_json_success(array(
				'results' => $domains,
				'message' => $message
			));
		} catch (\Exception $e) {
			wp_send_json_error(array('message' => $e->getMessage()));
		}
	}

	/**
	 * Create video upload ticket remotely via secure proxy.
	 */
	public function handle_create_video()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array('message' => __('Unauthorized action', 'upvimeo-direct-uploads')));
			exit;
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:disable WordPress.Security.NonceVerification.Missing
		$title = isset($_POST['title']) ? sanitize_text_field(wp_unslash($_POST['title'])) : __('Untitled', 'upvimeo-direct-uploads');
		$description = isset($_POST['description']) ? sanitize_textarea_field(wp_unslash($_POST['description'])) : '';
		$size = isset($_POST['size']) ? intval(wp_unslash($_POST['size'])) : 0;
		// phpcs:enable
		if ($size <= 0) {
			wp_send_json_error(array('message' => __('Invalid file size.', 'upvimeo-direct-uploads')));
		}

		$params = array(
			'name' => $title,
			'description' => $description,
		);

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if (isset($_POST['privacy'])) {
			// phpcs:ignore WordPress.Security.NonceVerification.Missing
			$privacy_view = sanitize_text_field(wp_unslash($_POST['privacy']));
			$params['privacy'] = array('view' => $privacy_view);
			if ($privacy_view === 'disable') {
				$embed_domains = $this->settings_helper->get_whitelisted_domains();
				
				try {
					// Fallback: If local settings are empty, pull from Vimeo account defaults directly.
					if (empty($embed_domains) && is_callable(array($this->api_helper, 'get_whitelist_domains'))) {
						$embed_domains = $this->api_helper->get_whitelist_domains();
					}
				} catch (\Exception $e) {
					// Silently fallback without crashing the TUS upload
				}

				if (!empty($embed_domains)) {
					$params['privacy']['embed'] = 'whitelist';
				} else {
					// Stop coercing to public! Let Vimeo inherit "whitelist" naturally if view=disable.
					// If the user hasn't explicitly populated local domains, they expect their account default to hold.
					$params['privacy']['embed'] = 'whitelist';
				}
			}
		}

		try {
			$attempt = $this->api_helper->create_upload_ticket($size, $params);
			if (isset($attempt['status']) && $attempt['status'] === 200) {

				if (isset($params['privacy']['embed']) && $params['privacy']['embed'] === 'whitelist') {
					$embed_domains = $this->settings_helper->get_whitelisted_domains();
					
					try {
						// Re-evaluate Fallback
						if (empty($embed_domains) && is_callable(array($this->api_helper, 'get_whitelist_domains'))) {
							$embed_domains = $this->api_helper->get_whitelist_domains();
						}
					} catch (\Exception $e) {
						// Ignore to prevent FATAL 500 error, just continue without syncing domains immediately
					}

					$access_token  = $this->settings_helper->get('upvimeo_access_token', '');
					$video_uri     = isset($attempt['body']['uri']) ? $attempt['body']['uri'] : '';

					if (!empty($embed_domains) && !empty($access_token) && !empty($video_uri)) {
						$video_id = str_replace('/videos/', '', $video_uri);

						foreach ($embed_domains as $domain) {
							if (empty($domain)) {
								continue;
							}

							$sanitized_domain = sanitize_text_field($domain);
							$request_url      = 'https://api.vimeo.com/videos/' . urlencode($video_id) . '/privacy/domains/' . rawurlencode($sanitized_domain);

							$response = wp_safe_remote_request(
								$request_url,
								array(
									'method'  => 'PUT',
									'headers' => array(
										'Authorization' => 'Bearer ' . sanitize_text_field(wp_unslash($access_token)),
										'Accept'        => 'application/vnd.vimeo.*+json;version=3.4',
										'Content-Type'  => 'application/json',
									),
								)
							);

							if (is_wp_error($response)) {
								$domain_filtered = esc_html($sanitized_domain);
								$err_msg         = esc_html($response->get_error_message());
								/* translators: 1: Allowed domain, 2: Error message */
								$message_str     = sprintf(esc_html__('Domain Whitelisting Error for %1$s: %2$s', 'upvimeo-direct-uploads'), $domain_filtered, $err_msg);
								$this->logger->log($message_str, 'upvimeo-ADMIN-API');
							}
						}
					}
				}

				wp_send_json_success($attempt['body']);
			} else {
				$error = isset($attempt['body']['error']) ? $attempt['body']['error'] : 'Unknown API error';
				wp_send_json_error(array('message' => $error));
			}
		} catch (\Exception $e) {
			wp_send_json_error(array('message' => $e->getMessage()));
		}
	}

	/**
	 * Search Vimeo account via secure proxy.
	 */
	public function handle_search_videos()
	{if (!current_user_can('upload_files')) {
			wp_send_json_error(array('message' => __('Unauthorized action', 'upvimeo-direct-uploads')));
		}

		check_ajax_referer('upvimeo_ajax_nonce', 'security');

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$query = isset($_GET['query']) ? sanitize_text_field(wp_unslash($_GET['query'])) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page = isset($_GET['page']) ? intval(wp_unslash($_GET['page'])) : 1;

		try {
			$response = $this->api_helper->get_my_videos(array('query' => $query, 'page' => $page));
			wp_send_json_success(array('data' => $response['results']));
		} catch (Exception $e) {
			wp_send_json_error(array('message' => $e->getMessage()));
		}
	}
}
