/home/sylamedg/www/wp-content/plugins/templately/includes/API/AIContent.php
<?php

/**
 * Templately AI Content Importer
 *
 * @package Templately
 * @since 1.0.0
 */

namespace Templately\API;

use Error;
use Exception;
use Templately\Utils\Helper;
use WP_REST_Request;
use WP_Error;
use Templately\Core\Importer\Utils\Utils;
use Templately\Core\Importer\Utils\AIUtils;
use Templately\Core\Importer\Utils\SignatureVerifier;
use Templately\Core\Importer\Parsers\WXR_Parser;

class AIContent extends API {
	private $endpoint  = 'ai-content';
	private $dev_mode  = false;


	/**
	 * AIContent constructor.
	 *
	 * @param string $file    File path.
	 * @param array  $settings Settings.
	 */
	public function __construct() {

		parent::__construct();

	}

	public function _permission_check(WP_REST_Request $request) {
		$this->request = $request;
		$this->api_key = $this->utils('options')->get( 'api_key' );
		$process_id    = $this->get_param('process_id');

		$_route = $request->get_route();
		if ('/templately/v1/ai-content/ai-update' === $_route || '/templately/v1/ai-content/ai-update-preview' === $_route) {
			Helper::log( [
				'headers' => $request->get_headers(),
				'body'    => $request->get_params(),
			], 'ai_update_request' );

			if (empty($process_id)) {
				return $this->error('invalid_id', __('Invalid ID.', 'templately'), 'calculate_credit', 400);
			}

			$header_api_key = sanitize_text_field($request->get_header('x_templately_apikey'));
			if (empty($header_api_key)) {
				$header_api_key = sanitize_text_field($request->get_header('X-Templately-Apikey'));
			}

			// Validate API key from header against database
			if (empty($header_api_key)) {
				return $this->error('missing_api_key', __('Missing API key in header.', 'templately'), 'ai-content/permission', 403);
			}

			$is_valid_key = $this->validate_api_key_in_db($header_api_key);
			if (!$is_valid_key) {
				return $this->error('invalid_api_key', __('Invalid API key provided in header.', 'templately'), 'ai-content/permission', 403);
			}

			// Check AI process data using API key-based storage
			$ai_process_data = AIUtils::get_ai_process_data();
			if (is_array($ai_process_data) && !empty($ai_process_data[$process_id])) {
				return true;
			}

			return (bool) AIUtils::get_matched_session_data($process_id);
		}

		// // Allow access to attachments endpoint
		// if ('/templately/v1/ai-content/attachments' === $_route) {
		// 	return true;
		// }
		return parent::_permission_check($request);
	}


	public function register_routes() {
		// $this->get( $this->endpoint . '/calculate-credit', [ $this, 'calculate_credit' ] );
		$this->post($this->endpoint . '/modify-content', [$this, 'modify_content']);
		$this->post($this->endpoint . '/ai-update', [$this, 'ai_update']);
		$this->post($this->endpoint . '/ai-update-preview', [$this, 'ai_update_preview']);
		$this->post($this->endpoint . '/generate-logo', [$this, 'generate_logo']);
		$this->post($this->endpoint . '/generate-meta', [$this, 'generate_meta']);
		$this->get($this->endpoint . '/attachments', [$this, 'get_attachments'], [
			'type' => [
				'default' => 'pack',
				'required' => false,
				'sanitize_callback' => 'sanitize_text_field',
			],
			'id' => [
				'required' => false,
				'sanitize_callback' => 'sanitize_text_field',
			],
			'pack_id' => [
				'required' => false,
				'sanitize_callback' => 'sanitize_text_field',
			],
		]);
		$this->get($this->endpoint . '/images', [$this, 'search_images'], [
			'query' => [
				'required' => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => function($param, $request, $key) {
					return is_string($param) && strlen($param) <= 255;
				},
			],
			'orientation' => [
				'required' => false,
				'default' => 'all',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => function($param, $request, $key) {
					$allowed_orientations = ['all', 'landscape', 'portrait', 'square'];
					return in_array($param, $allowed_orientations, true);
				},
			],
			'size' => [
				'required' => false,
				'default' => 'medium',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => function($param, $request, $key) {
					$allowed_sizes = ['small', 'medium', 'large'];
					return in_array($param, $allowed_sizes, true);
				},
			],
			'color' => [
				'required' => false,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => function($param, $request, $key) {
					return is_string($param) && strlen($param) <= 50;
				},
			],
			'page' => [
				'required' => false,
				'default' => 1,
				'sanitize_callback' => 'absint',
				'validate_callback' => function($param, $request, $key) {
					return is_numeric($param) && $param > 0 && $param <= 1000;
				},
			],
			'per_page' => [
				'required' => false,
				'default' => 20,
				'sanitize_callback' => 'absint',
				'validate_callback' => function($param, $request, $key) {
					return is_numeric($param) && $param > 0 && $param <= 100;
				},
			],
		]);
		// die(rest_url( 'templately/v1/ai-content/ai-update' ));
	}

	public function calculate_credit() {
		$pack_id = $this->get_param('pack_id');

		return [
			'status' => 'success',
			'data'   => [
				'availableCredit' => 100,
			],
		];

		if (empty($pack_id)) {
			return $this->error('invalid_id', __('Invalid ID.', 'templately'), 'calculate_credit', 400);
		}

		$extra_headers = [
			'Accept' => 'application/json',
		];
		$response = Helper::make_api_get_request("v2/ai/calculate-credit/pack/$pack_id", [], $extra_headers, 30);


		// return $response;
		if (is_wp_error($response)) {
			return $this->error('request_failed', __('Request failed.', 'templately'), 'calculate_credit', 500, $response);
		}

		$body = wp_remote_retrieve_body($response);
		$data = json_decode($body, true);
		// error status is ok
		if (! is_array($data) || ! isset($data['status'])) {
			return $this->error('invalid_response', __('Invalid response.', 'templately'), 'calculate_credit', 500);
		}


		return $data;
	}

	public function modify_content() {
		add_filter('wp_redirect', '__return_false', 999);
		set_time_limit(3 * MINUTE_IN_SECONDS);
		ini_set('max_execution_time', 3 * MINUTE_IN_SECONDS);

		$pack_id             = $this->get_param('pack_id');
		$isBusinessNichesNew = $this->get_param('isBusinessNichesNew', false);
		$ai_page_ids         = $this->get_param('ai_page_ids', [], null);
		$content_ids         = $this->get_param('content_ids', [], null);
		$session_id          = $this->get_param('session_id');                  // Add session_id parameter

		// Security: Sanitize session_id if provided
		if (!empty($session_id)) {
			$session_id = AIUtils::sanitize_path_component($session_id, 'session_id');
			if (is_wp_error($session_id)) {
				return $session_id;
			}
		}

		$preview_pages       = $this->get_param('preview_pages', [], null);
		$image_replace       = $this->get_param('imageReplace', [], null);
		$platform            = $this->get_param('platform');
		$language            = $this->get_param('language', 'English');

		// ai content fields
		$name               = $this->get_param('name');
		$category           = $this->get_param('category');
		$description        = $this->get_param('description');
		$email              = $this->get_param('email');
		$contactNumber      = $this->get_param('contactNumber');
		$businessAddress    = $this->get_param('businessAddress');
		$openingHour        = $this->get_param('openingHour');
		$requested_platform = $this->get_param('requested_platform', 'templately');

		if (empty($pack_id)) {
			return $this->error('invalid_id', __('Invalid ID.', 'templately'), 'modify_content', 400);
		}
		if (empty($category)) {
			return $this->error('invalid_prompt', __('Invalid prompt.', 'templately'), 'modify_content', 400);
		}
		if (empty($content_ids) && empty($preview_pages)) {
			return $this->error('invalid_content_ids', __('Invalid content ids.', 'templately'), 'modify_content', 400);
		}
		if (empty($platform)) {
			return $this->error('invalid_platform', __('Invalid platform.', 'templately'), 'modify_content', 400);
		}


		// $response    = get_transient( '__templately_ai_process_id' );

		// if(empty($response)) {
		$extra_headers = [
			'Accept'                          => 'application/json',
			'x-templately-session-id'         => $session_id,
			'x-templately-requested-platform' => $requested_platform,
		];
		$body_data = [
			'business_name'   => $name,
			'business_niches' => $category,
			'prompt'          => $description,
			'email'           => $email,
			'phone'           => $contactNumber,
			'address'         => $businessAddress,
			'openingHour'     => $openingHour,
			'pack_id'         => $pack_id,
			'content_ids'     => $content_ids,
			'platform'        => $platform,
			'preview_pages'   => $preview_pages,
			'language'        => $language,
			'callback'        => defined('TEMPLATELY_CALLBACK') ? TEMPLATELY_CALLBACK . '/wp-json/templately/v1/ai-content/ai-update' : rest_url('templately/v1/ai-content/ai-update'),
		];
		$response = Helper::make_api_post_request('v2/ai/modify-content/pack', $body_data, $extra_headers, 15 * MINUTE_IN_SECONDS);

		// 	set_transient( '__templately_ai_process_id', $response, 60 * 60 * 24 * 30 );
		// }

		$bk_ai_business_niches = get_option('templately_ai_business_niches', []);
		if (!empty($business_niches) && $isBusinessNichesNew && ! in_array($business_niches, $bk_ai_business_niches)) {
			$bk_ai_business_niches[] = $business_niches;
			update_option('templately_ai_business_niches', $bk_ai_business_niches, false);
		}

		// return $response;
		if (is_wp_error($response)) {
			error_log(print_r($response, true));
			return $this->error('request_failed', __('Request failed.', 'templately'), 'modify_content', 500, $response->get_error_data());
		}

		$body = wp_remote_retrieve_body($response);
		$data = json_decode($body, true);
		// error status is ok, if status is error then return as is
		if (! is_array($data) || ! isset($data['status'])) {
			return $this->error('invalid_response', __('Invalid response.', 'templately'), 'modify_content', 500, $data);
		}

		// "{"status":"success","message":"The content is being generated in the queue","process_id":"01JRQQD39GNWTNF18EWF8YH0BG-271838-pack-408"}"
		if (isset($data['status']) && $data['status'] === 'success' && isset($data['process_id'])) {
			$process_id = $data['process_id'];

			// // Save templates to files if available using the common function
			// if (!empty($data['templates']) && is_array($data['templates'])) {
			// 	foreach ($data['templates'] as $content_id => $template_data) {
			// 		// Decode template if it's base64 encoded
			// 		if (! empty($template_data) && base64_decode($template_data, true) !== false) {
			// 			$data['templates'][$content_id] = base64_decode($template_data);
			// 		}

			// 		if (!empty($template_data)) {
			// 			AIUtils::save_template_to_file(
			// 				$process_id,
			// 				$content_id,
			// 				$template_data,
			// 				$ai_page_ids,
			// 				true, // Always use preview mode for AI content workflow
			// 				isset($template_data['isSkipped']) ? $template_data['isSkipped'] : false
			// 			);
			// 		}
			// 	}
			// }

			$user = $this->utils('options')->get('user');

			$ai_process_data[$process_id] = [
				'name'            => $name,
				'category'        => $category,
				'description'     => $description,
				'email'           => $email,
				'contactNumber'   => $contactNumber,
				'businessAddress' => $businessAddress,
				'openingHour'     => $openingHour,
				'process_id'      => $process_id,
				'pack_id'         => $pack_id,
				'ai_page_ids'     => $ai_page_ids,
				'ai_preview_ids'  => $preview_pages,
				'content_ids'     => $content_ids,
				'platform'        => $platform,
				'api_key'         => $this->api_key,
				'user_id'         => isset($user['id']) ? $user['id'] : null,
				'session_id'      => $session_id,        // Store session_id for coordination
				'imageReplace'    => $image_replace,    // Store session_id for coordination
				'language'        => $language,
			];

			// Update using API key-based storage with automatic count-based cleanup
			AIUtils::update_ai_process_data($ai_process_data);

			return [
				'status'     => 'success',
				'message'    => __('The content is being generated in the queue', 'templately'),
				'process_id' => $process_id,
				'templates'  => !empty($data['templates']) ? $data['templates'] : null,
				'is_local_site'  => !empty($data['is_local_site']) ? $data['is_local_site'] : null,
			];
		}

		return $data;
	}

	public function ai_update() {
		add_filter('wp_redirect', '__return_false', 999);

		$template    = $this->get_param('template');
		$process_id  = $this->get_param('process_id');
		$template_id = $this->get_param('template_id');
		$content_id  = $this->get_param('content_id');
		$type        = $this->get_param('type');
		$isSkipped   = $this->get_param('isSkipped', false);
		$credit_cost = $this->request->get_param('credit_cost');

		error_log('process_id: ' . $process_id);

		// Handle credit cost updates separately
		if ($this->request->has_param('credit_cost')) {
			$processed_pages = get_option("templately_ai_processed_pages", []);
			$processed_pages[$process_id] = $processed_pages[$process_id] ?? [];
			$processed_pages[$process_id]['credit_cost'] = $credit_cost;
			update_option("templately_ai_processed_pages", $processed_pages, false);

			return [
				'status' => 'success',
				'data'   => [
					'process_id' => $process_id,
					'credit_cost' => $credit_cost,
				],
			];
		}

		// Always use preview mode for AI content workflow
		// Validate and get process data using centralized method
		$process_data = AIUtils::validate_and_get_process_data($process_id);
		if (is_wp_error($process_data)) {
			return $process_data;
		}

		$session_id = $process_data['session_id'];
		$ai_page_ids = $process_data['ai_page_ids'];

		// Use the common helper function to save the template
		$result = AIUtils::save_template_to_file(
			$process_id,
			$session_id,
			$content_id,
			$template,
			$ai_page_ids,
			$isSkipped
		);

		if(is_wp_error($result)){
			return $result;
		}

		// Return the result from the helper function
		if (isset($result['status']) && $result['status'] === 'success') {
			return $result;
		}

		// Return error if the helper function failed
		return $result;
	}

	public function ai_update_preview() {
		add_filter('wp_redirect', '__return_false', 999);

		$template   = $this->get_param('templates');         // Now expects an array with content_id as keys
		$process_id = $this->get_param('process_id');
		$isSkipped  = $this->get_param('isSkipped', false);
		$error      = $this->get_param('error', null);

		error_log('process_id: ' . $process_id);

		if (!empty($isSkipped) || !empty($error)) {
			// Update AI process data with error using API key-based storage
			$ai_process_data = AIUtils::get_ai_process_data();
			if (isset($ai_process_data[$process_id])) {
				$ai_process_data[$process_id]['preview_error'] = $error;
				AIUtils::update_ai_process_data($ai_process_data);
			}
			wp_send_json_error([
				'status' => 'error',
				'message' => $error,
			]);
		}

		// Validate template parameter is an array
		if (!is_array($template) || empty($template)) {
			return $this->error('invalid_template', __('Template must be a non-empty array with content_id as keys.', 'templately'), 'ai-content/ai-update-preview', 400);
		}

		// Always use preview mode for AI content workflow
		// Validate and get process data using centralized method
		$process_data = AIUtils::validate_and_get_process_data($process_id);
		if (is_wp_error($process_data)) {
			return $process_data;
		}

		$session_id = $process_data['session_id'];
		$ai_page_ids = $process_data['ai_page_ids'];
		$results = [];
		$success_count = 0;
		$error_count = 0;

		// Process each content_id/template pair
		foreach ($template as $content_id => $template_data) {
			// Use the common helper function to save the template (always preview mode)
			$result = AIUtils::save_template_to_file(
				$process_id,
				$session_id,
				$content_id,
				$template_data,
				$ai_page_ids,
				$isSkipped
			);

			$results[$content_id] = $result;

			// Track success/error counts
			if (isset($result['status']) && $result['status'] === 'success') {
				$success_count++;
			} else {
				$error_count++;
			}
		}

		// Return consolidated response
		$overall_status = $error_count === 0 ? 'success' : ($success_count === 0 ? 'error' : 'partial_success');

		// Note: No cleanup needed with API key-based storage and count-based management

		return [
			'status' => $overall_status,
			'message' => sprintf(
				__('Processed %d templates: %d successful, %d failed.', 'templately'),
				count($template),
				$success_count,
				$error_count
			),
		];
	}

	/**
	 * Get attachments from API endpoint
	 *
	 * @return array
	 */
	public function get_attachments() {
		// Get parameters from request
		$type = $this->get_param('type', 'pack');
		$id = $this->get_param('pack_id');

		// Require ID parameter - return error if not provided
		if (empty($id)) {
			return $this->error('missing_id', __('Pack ID or ID parameter is required.', 'templately'), 'get_attachments', 400);
		}

		try {
			// Construct API endpoint URL
			$api_endpoint = "get-xml-attachment/{$type}/{$id}";

			// Make API call
			$extra_headers = [
				'Accept' => 'application/xml, text/xml',
			];
			$response = Helper::make_api_get_request("v2/$api_endpoint", [], $extra_headers, 30);

			// Check for HTTP errors
			if (is_wp_error($response)) {
				return $this->error('api_request_failed', __('Failed to fetch attachments from API.', 'templately'), 'get_attachments', 500, $response->get_error_message());
			}

			$response_code = wp_remote_retrieve_response_code($response);
			$xml_content = wp_remote_retrieve_body($response);

			if ($response_code !== 200) {
				// check if $xml_content contains valid json
				// ex. '{"status":"error","message":"Attachment XML file not found in pack archive."}'
				$error_data = @json_decode($xml_content, true);
				if(is_array($error_data) && isset($error_data['status']) && $error_data['status'] === 'error' && !empty($error_data['message'])){
					return $this->error('api_http_error', $error_data['message'], 'get_attachments', $response_code);
				}
				return $this->error('api_http_error', sprintf(__('API returned HTTP %d error.', 'templately'), $response_code), 'get_attachments', $response_code);
			}

			// Validate we have XML content
			if (empty($xml_content)) {
				return $this->error('no_xml_content', __('No XML content found in API response.', 'templately'), 'get_attachments', 404);
			}

			// Parse the XML content from API response
			$parsed_data = $this->parse_xml_content($xml_content);

			if (is_wp_error($parsed_data)) {
				return $this->error('xml_parse_error', __('Failed to parse XML content.', 'templately'), 'get_attachments', 500, $parsed_data->get_error_message());
			}

			// Extract attachments from parsed data
			$attachments = $this->extract_attachments_from_parsed_data($parsed_data);

			return [
				'status' => 'success',
				'data' => $attachments,
				'message' => sprintf(__('Found %d attachments.', 'templately'), count($attachments)),
			];

		} catch (Exception $e) {
			return $this->error('exception', __('An unexpected error occurred while fetching attachments.', 'templately'), 'get_attachments', 500, $e->getMessage());
		}
	}



	/**
	 * Parse XML content string using WXR Parser
	 *
	 * @param string $xml_content XML content string
	 * @return array|WP_Error Parsed data or error
	 */
	private function parse_xml_content($xml_content) {
		// Ensure WordPress filesystem functions are available
		if (!function_exists('wp_tempnam')) {
			require_once(ABSPATH . 'wp-admin/includes/file.php');
		}

		// Create a temporary file to store XML content
		$temp_file = wp_tempnam('templately_attachments');
		if (!$temp_file) {
			return new WP_Error('temp_file_failed', __('Failed to create temporary file.', 'templately'));
		}

		// Write XML content to temporary file
		$bytes_written = file_put_contents($temp_file, $xml_content);
		if ($bytes_written === false) {
			unlink($temp_file);
			return new WP_Error('write_failed', __('Failed to write XML content to temporary file.', 'templately'));
		}

		try {
			// Initialize WXR Parser
			$parser = new WXR_Parser();

			// Parse the temporary XML file
			$parsed_data = $parser->parse($temp_file);

			// Clean up temporary file
			unlink($temp_file);

			return $parsed_data;

		} catch (Exception $e) {
			// Clean up temporary file on exception
			if (file_exists($temp_file)) {
				unlink($temp_file);
			}
			return new WP_Error('parse_exception', $e->getMessage());
		}
	}

	/**
	 * Extract attachments from parsed WXR data
	 *
	 * @param array $parsed_data Parsed WXR data
	 * @return array Array of attachment data
	 */
	private function extract_attachments_from_parsed_data($parsed_data) {
		$attachments = [];

		if (isset($parsed_data['posts']) && is_array($parsed_data['posts'])) {
			foreach ($parsed_data['posts'] as $post) {
				// Check if this is an attachment
				if (isset($post['post_type']) && $post['post_type'] === 'attachment') {
					$attachment = [
						'id' => isset($post['post_id']) ? (int) $post['post_id'] : 0,
						'url' => isset($post['attachment_url']) ? (string) $post['attachment_url'] : '',
						'title' => isset($post['post_title']) ? (string) $post['post_title'] : '',
						'type' => isset($post['attachment_type']) ? (string) $post['attachment_type'] : '',
					];

					// Extract metadata including dimensions and medium URL
					$metadata = $this->extract_medium_size_url($post, $attachment['url']);

					// Filter out small images (width or height <= 150px) to ignore small icons
					if ($metadata && isset($metadata['width']) && isset($metadata['height'])) {
						if ($metadata['width'] < 150 || $metadata['height'] < 150) {
							continue; // Skip small images/icons
						}

						// Add dimensions to attachment data
						$attachment['width'] = $metadata['width'];
						$attachment['height'] = $metadata['height'];

						// Add medium URL if available
						if (isset($metadata['medium_url'])) {
							$attachment['medium_url'] = $metadata['medium_url'];
						}
					} else {
						// Skip attachments without metadata or dimensions
						continue;
					}

					// Only add if we have the required data
					if ($attachment['id'] && $attachment['url'] && $attachment['title']) {
						$attachments[] = $attachment;
					}
				}
			}
		}

		return $attachments;
	}

	/**
	 * Extract medium size URL from attachment metadata and get image dimensions
	 *
	 * @param array $post Post data from WXR parser
	 * @param string $original_url Original attachment URL
	 * @return array|null Array with medium_url and dimensions if found, null otherwise
	 */
	private function extract_medium_size_url($post, $original_url) {
		if (!isset($post['postmeta']) || !is_array($post['postmeta'])) {
			return null;
		}

		foreach ($post['postmeta'] as $meta) {
			if (!isset($meta['key']) || !isset($meta['value'])) {
				continue;
			}

			// Only check _wp_attachment_metadata
			if ($meta['key'] === '_wp_attachment_metadata') {
				$attachment_metadata = @unserialize($meta['value']);
				if (is_array($attachment_metadata)) {
					$result = [];

					// Get original image dimensions
					$width = isset($attachment_metadata['width']) ? (int) $attachment_metadata['width'] : 0;
					$height = isset($attachment_metadata['height']) ? (int) $attachment_metadata['height'] : 0;

					$result['width'] = $width;
					$result['height'] = $height;

					// Check if medium size exists
					if (isset($attachment_metadata['sizes']['medium']['file'])) {
						// Construct medium URL from original URL and medium filename
						$medium_filename = $attachment_metadata['sizes']['medium']['file'];
						$original_path = dirname(parse_url($original_url, PHP_URL_PATH));
						$base_url = str_replace(parse_url($original_url, PHP_URL_PATH), '', $original_url);
						$result['medium_url'] = $base_url . $original_path . '/' . $medium_filename;
					}

					return $result;
				}
			}
		}

		return null;
	}



	/**
	 * Search images endpoint
	 *
	 * @param WP_REST_Request $request
	 * @return WP_REST_Response|WP_Error
	 */
	public function search_images(WP_REST_Request $request) {
		// Get and sanitize parameters
		$query = $this->get_param('query', '');
		$orientation = $this->get_param('orientation', 'all');
		$size = $this->get_param('size', 'medium');
		$color = $this->get_param('color', '');
		$page = $this->get_param('page', 1, 'absint');
		$per_page = $this->get_param('per_page', 20, 'absint');

		// Validate required query parameter
		if (empty($query)) {
			return $this->error(
				'missing_query',
				__('Search query is required.', 'templately'),
				'search_images',
				400
			);
		}

		// Prepare API request parameters
		$api_params = [
			'query' => urlencode($query),
			'page' => $page,
			'per_page' => $per_page,
		];

		// Add optional parameters if provided
		if ($orientation !== 'all') {
			$api_params['orientation'] = $orientation;
		}

		if (!empty($size)) {
			$api_params['size'] = $size;
		}

		if (!empty($color)) {
			$api_params['color'] = $color;
		}

		// Make API request to external image service
		$extra_headers = [
			'Content-Type' => 'application/json',
		];

		$response = Helper::make_api_get_request('v2/images', $api_params, $extra_headers, 30);

		// Handle API response errors
		if (is_wp_error($response)) {
			return $this->error(
				'api_request_failed',
				__('Failed to fetch images from external service.', 'templately'),
				'search_images',
				500
			);
		}

		$response_code = wp_remote_retrieve_response_code($response);
		$response_body = wp_remote_retrieve_body($response);

		if ($response_code !== 200) {
			return $this->error(
				'api_response_error',
				sprintf(__('External API returned error code: %d', 'templately'), $response_code),
				'search_images',
				$response_code
			);
		}

		// Parse and validate response
		$data = json_decode($response_body, true);
		if (json_last_error() !== JSON_ERROR_NONE) {
			return $this->error(
				'invalid_response',
				__('Invalid response from external service.', 'templately'),
				'search_images',
				500
			);
		}

		// Check if the response has the expected structure and success status
		if (!isset($data['status']) || $data['status'] !== 'success') {
			return $this->error(
				'api_response_error',
				__('External API returned an error status.', 'templately'),
				'search_images',
				500
			);
		}

		// Extract nested data from the response
		$response_data = $data['data'] ?? [];
		$images = $response_data['images'] ?? [];
		$total_results = $response_data['total_results'] ?? 0;
		$current_page = $response_data['page'] ?? $page;
		$per_page_count = $response_data['per_page'] ?? $per_page;

		// Return successful response with properly mapped data
		return $this->success([
			'images' => $images,
			'total' => $total_results,
			'page' => $current_page,
			'per_page' => $per_page_count,
			'total_pages' => $total_results > 0 ? ceil($total_results / $per_page_count) : 0,
		]);
	}

	/**
	 * Generate logo using AI
	 *
	 * @return array|WP_Error
	 */
	public function generate_logo() {
		// Get parameters
		$business_name = $this->get_param('business_name', '');
		$description = $this->get_param('description');
		$logo_type = $this->get_param('logo_type');
		$requested_platform = $this->get_param('requested_platform', 'templately');

		// Validate required parameters
		if (empty($description)) {
			return $this->error(
				'missing_description',
				__('Description is required for logo generation.', 'templately'),
				'generate_logo',
				400
			);
		}

		if (empty($logo_type)) {
			return $this->error(
				'missing_logo_type',
				__('Logo type is required.', 'templately'),
				'generate_logo',
				400
			);
		}

		// Prepare request body
		$body_data = [
			'business_name' => $business_name,
			'description' => $description,
			'logo_type' => $logo_type,
		];

		// Make API request
		$extra_headers = [
			'Content-Type' => 'application/json',
			'x-templately-requested-platform' => $requested_platform,
		];

		$response = Helper::make_api_post_request('v2/generate-logo', $body_data, $extra_headers, 60);

		// Handle API response errors
		if (is_wp_error($response)) {
			return $this->error(
				'api_request_failed',
				__('Something went wrong. Please try again or contact support.', 'templately'),
				'generate_logo',
				500,
				$response->get_error_message()
			);
		}

		$response_code = wp_remote_retrieve_response_code($response);
		$response_body = wp_remote_retrieve_body($response);

		if ($response_code !== 200) {
			// Try to parse the response body as JSON to get specific error details
			$data = json_decode($response_body, true);

			// If valid JSON, extract error message and return with proper status code
			if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
				$error_message = isset($data['message']) ? $data['message'] : __('Something went wrong. Please try again or contact support.', 'templately');
				return $this->error(
					'api_response_error',
					$error_message,
					'generate_logo',
					$response_code
				);
			}

			// Otherwise, return generic error
			return $this->error(
				'api_response_error',
				__('Something went wrong. Please try again or contact support.', 'templately'),
				'generate_logo',
				$response_code
			);
		}

		// Parse and validate response
		$data = json_decode($response_body, true);
		if (json_last_error() !== JSON_ERROR_NONE) {
			return $this->error(
				'invalid_response',
				__('Invalid response from API.', 'templately'),
				'generate_logo',
				500
			);
		}

		// Check if the response has the expected structure
		if (!isset($data['status'])) {
			return $this->error(
				'api_response_error',
				__('API returned an unexpected response.', 'templately'),
				'generate_logo',
				500
			);
		}

		// Extract image_base64 from nested data field if present
		$image_base64 = null;
		if (isset($data['data']['image_base64'])) {
			$image_base64 = $data['data']['image_base64'];
		} elseif (isset($data['image_base64'])) {
			// Fallback for legacy response format
			$image_base64 = $data['image_base64'];
		}

		// Upload base64 image to media library if provided
		if (!empty($image_base64)) {
			$upload_result = Utils::upload_logo_base64($image_base64);

			if (is_array($upload_result) && isset($upload_result['error'])) {
				// Log error but don't fail the entire response
				error_log('Logo upload error: ' . $upload_result['error']);
			} else if (is_array($upload_result) && isset($upload_result['id'])) {
				// Return clean response with only essential uploaded logo information
				// Overwrite the data field to remove base64 image data and return only ID and URL
				return [
					'status' => 'success',
					'data' => [
						'id' => $upload_result['id'],
						'url' => $upload_result['url'],
					],
				];
			}
		}

		// Return the original response if no logo was uploaded
		return $data;
	}

	/**
	 * Generate meta (title or tagline) using AI
	 *
	 * @return array|WP_Error
	 */
	public function generate_meta() {
		// Get parameters
		$field = $this->get_param('field');
		$text = $this->get_param('text');
		$requested_platform = $this->get_param('requested_platform', 'templately');

		// Validate required parameters
		if (empty($field)) {
			return $this->error(
				'missing_field',
				__('Field is required.', 'templately'),
				'generate_meta',
				400
			);
		}

		if (empty($text)) {
			return $this->error(
				'missing_text',
				__('Text is required for meta generation.', 'templately'),
				'generate_meta',
				400
			);
		}

		// Prepare request body
		$body_data = [
			'field' => $field,
			'text' => $text,
		];

		// Make API request
		$extra_headers = [
			'Content-Type' => 'application/json',
			'x-templately-requested-platform' => $requested_platform,
		];

		$response = Helper::make_api_post_request('v2/generate-meta', $body_data, $extra_headers, 30);

		// Handle API response errors
		if (is_wp_error($response)) {
			return $this->error(
				'api_request_failed',
				__('Failed to generate meta.', 'templately'),
				'generate_meta',
				500,
				$response->get_error_message()
			);
		}

		$response_code = wp_remote_retrieve_response_code($response);
		$response_body = wp_remote_retrieve_body($response);

		if ($response_code !== 200) {
			// Try to parse the response body as JSON to get specific error details
			$data = json_decode($response_body, true);

			// If valid JSON, extract error message and return with proper status code
			if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
				$error_message = isset($data['message']) ? $data['message'] : __('Something went wrong. Please try again or contact support.', 'templately');
				return $this->error(
					'api_response_error',
					$error_message,
					'generate_meta',
					$response_code
				);
			}

			// Otherwise, return generic error
			return $this->error(
				'api_response_error',
				__('Something went wrong. Please try again or contact support.', 'templately'),
				'generate_meta',
				$response_code
			);
		}

		// Parse and validate response
		$data = json_decode($response_body, true);
		if (json_last_error() !== JSON_ERROR_NONE) {
			return $this->error(
				'invalid_response',
				__('Invalid response from API.', 'templately'),
				'generate_meta',
				500
			);
		}

		// Check if the response has the expected structure
		if (!isset($data['status'])) {
			return $this->error(
				'api_response_error',
				__('API returned an unexpected response.', 'templately'),
				'generate_meta',
				500
			);
		}

		// Return the response as-is
		return $data;
	}

	/**
	 * Validate API key against database
	 * Checks if the provided API key exists for any user on the current site
	 * Handles both single-site and multisite WordPress installations
	 *
	 * @param string $api_key The API key to validate
	 * @return bool True if valid, false otherwise
	 */
	private function validate_api_key_in_db($api_key) {
		global $wpdb;

		$api_key = sanitize_text_field($api_key);

		if (empty($api_key)) {
			return false;
		}

		$meta_key = '_templately_api_key';

		// Handle multisite: key will have site prefix in multisite
		if (is_multisite()) {
			// get_user_option() uses the format: {$wpdb->base_prefix}{$blog_id}_{$meta_key}
			// For current blog, we need to check with the current blog prefix
			$blog_id = get_current_blog_id();
			$meta_key = $wpdb->get_blog_prefix($blog_id) . $meta_key;
		}

		// Query to check if this API key exists for any user
		$query = $wpdb->prepare(
			"SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1",
			$meta_key,
			$api_key
		);

		$user_id = $wpdb->get_var($query);

		return !empty($user_id);
	}
}