<?php
/**
 * Review API Endpoints
 *
 * @package Ugcify\Admin\API
 */

namespace Ugcify\Admin\API;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Ugcify\Storage\StorageManager;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

/**
 * Class ReviewAPI

 * phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value
 */
class ReviewAPI extends WP_REST_Controller {
	/**
	 * Namespace
	 *
	 * @var string
	 */
	protected $namespace = 'ugcify/v1';

	/**
	 * Rest base
	 *
	 * @var string
	 */
	protected $rest_base = 'reviews';

	/**
	 * Register routes
	 */
	public function register_routes() {
		// Submit review.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_review' ),
					'permission_callback' => array( $this, 'check_create_permission' ),
					'args'                => $this->get_review_schema(),
				),
			)
		);

		// Upload media.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/upload',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'upload_media' ),
					'permission_callback' => array( $this, 'check_upload_permission' ),
				),
			)
		);
	}

	/**
	 * Check create permission
	 *
	 * @return bool|WP_Error
	 */
	public function check_create_permission() {
		// Get settings.
		$settings = get_option( 'ugcify_review_form_settings', array(
			'formVisibility' => 'logged-in',
		) );

		$visibility = isset( $settings['formVisibility'] ) ? $settings['formVisibility'] : 'logged-in';

		switch ( $visibility ) {
			case 'anyone':
				return true;

			case 'logged-in':
				if ( ! is_user_logged_in() ) {
					return new WP_Error(
						'rest_forbidden',
						__( 'You must be logged in to submit a review.', 'ugcify' ),
						array( 'status' => 401 )
					);
				}
				return true;

			case 'verified-buyers':
				if ( ! is_user_logged_in() ) {
					return new WP_Error(
						'rest_forbidden',
						__( 'You must be logged in to submit a review.', 'ugcify' ),
						array( 'status' => 401 )
					);
				}
				// Verification will be done in create_review.
				return true;

			default:
				return new WP_Error(
					'rest_forbidden',
					__( 'You are not allowed to submit reviews.', 'ugcify' ),
					array( 'status' => 403 )
				);
		}
	}

	/**
	 * Check upload permission
	 *
	 * @return bool|WP_Error
	 */
	public function check_upload_permission() {
		// For now, allow anyone who can create reviews to upload.
		return $this->check_create_permission();
	}

	/**
	 * Upload media file
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function upload_media( $request ) {
		$files = $request->get_file_params();

		if ( empty( $files['file'] ) ) {
			return new WP_Error(
				'no_file',
				__( 'No file uploaded.', 'ugcify' ),
				array( 'status' => 400 )
			);
		}

		$file = $files['file'];

		// Determine size limit from form settings, falling back to 50 MB for videos and 10 MB for images.
		$form_settings = get_option( 'ugcify_review_form_settings', array() );
		$is_video      = isset( $file['type'] ) && strncmp( (string) $file['type'], 'video/', 6 ) === 0;
		if ( $is_video ) {
			$limit_mb = isset( $form_settings['maxVideoSizeMb'] ) ? max( 1, (int) $form_settings['maxVideoSizeMb'] ) : 50;
		} else {
			$limit_mb = isset( $form_settings['mediaMaxSizeMb'] ) ? max( 1, (int) $form_settings['mediaMaxSizeMb'] )
				: ( isset( $form_settings['maxImageSizeMb'] ) ? max( 1, (int) $form_settings['maxImageSizeMb'] ) : 10 );
		}
		$max_size = $limit_mb * 1024 * 1024;

		if ( $file['size'] > $max_size ) {
			return new WP_Error(
				'file_too_large',
				/* translators: %d: maximum file size in MB */
				sprintf( __( 'File size must be less than %d MB.', 'ugcify' ), $limit_mb ),
				array( 'status' => 400 )
			);
		}

		// Validate file type.
		$allowed_types = array(
			'image/jpeg',
			'image/jpg',
			'image/png',
			'image/gif',
			'image/webp',
			'video/mp4',
			'video/quicktime',
			'video/x-msvideo',
			'video/x-matroska',
		);

		if ( ! in_array( $file['type'], $allowed_types, true ) ) {
			return new WP_Error(
				'invalid_file_type',
				__( 'Invalid file type. Allowed types: JPEG, PNG, GIF, WebP, MP4, MOV, AVI, MKV.', 'ugcify' ),
				array( 'status' => 400 )
			);
		}

		// ── S3 upload path ──────────────────────────────────────────────────
		$storage = new StorageManager();
		if ( $storage->is_enabled() ) {
			$product_id   = absint( $request->get_param( 'product_id' ) );
			$product_name = sanitize_text_field( (string) $request->get_param( 'product_name' ) );
			$product_name = $this->resolve_product_name_for_upload( $product_id, $product_name );
			$review_id    = absint( $request->get_param( 'review_id' ) );
			$date_folder  = $this->resolve_review_date_folder_for_upload( $review_id );
			$replace_url  = esc_url_raw( (string) $request->get_param( 'replace_source_url' ) );
			$replace_key  = $this->extract_replace_object_key_from_url( $storage, $replace_url );

			if ( '' !== $replace_key ) {
				$result = $storage->upload_with_object_key( $file, $replace_key );
			} else {
				$result = $storage->upload( $file, $product_id, $product_name, $date_folder );
			}
			if ( is_wp_error( $result ) ) {
				return $result;
			}

			return rest_ensure_response(
				array(
					'success' => true,
					'data'    => array(
						'id'   => 0,
						'url'  => $result['url'],
						'type' => $result['type'],
						'name' => $result['name'],
					),
				)
			);
		}

		// ── Original local upload path ──────────────────────────────────────
		// Use WordPress file handling.
		require_once ABSPATH . 'wp-admin/includes/file.php';
		require_once ABSPATH . 'wp-admin/includes/media.php';
		require_once ABSPATH . 'wp-admin/includes/image.php';

		$ugcify_allowed_mimes = array(
			'jpg|jpeg|jpe' => 'image/jpeg',
			'png'          => 'image/png',
			'gif'          => 'image/gif',
			'webp'         => 'image/webp',
			'mp4'          => 'video/mp4',
			'mov'          => 'video/quicktime',
			'avi'          => 'video/x-msvideo',
			'mkv'          => 'video/x-matroska',
		);

		// Allow video MIME types for the upload regardless of user role.
		$ugcify_mime_filter = static function ( $mimes ) use ( $ugcify_allowed_mimes ) {
			return array_merge( (array) $mimes, $ugcify_allowed_mimes );
		};

		// Prevent wp_check_filetype_and_ext from rejecting video types when
		// the server's MIME detection disagrees with the browser-reported type.
		$ugcify_filetype_filter = static function ( $checked, $file_path, $filename, $mimes ) {
			if ( ! empty( $checked['ext'] ) ) {
				return $checked;
			}
			$ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
			$video_map = array(
				'mp4' => 'video/mp4',
				'mov' => 'video/quicktime',
				'avi' => 'video/x-msvideo',
				'mkv' => 'video/x-matroska',
			);
			if ( isset( $video_map[ $ext ] ) ) {
				return array(
					'ext'             => $ext,
					'type'            => $video_map[ $ext ],
					'proper_filename' => false,
				);
			}
			return $checked;
		};

		add_filter( 'upload_mimes', $ugcify_mime_filter, 99 );
		add_filter( 'wp_check_filetype_and_ext', $ugcify_filetype_filter, 99, 4 );

		// Upload file.
		$upload = wp_handle_upload(
			$file,
			array(
				'test_form' => false,
				'mimes'     => $ugcify_allowed_mimes,
			)
		);

		remove_filter( 'upload_mimes', $ugcify_mime_filter, 99 );
		remove_filter( 'wp_check_filetype_and_ext', $ugcify_filetype_filter, 99 );

		if ( isset( $upload['error'] ) ) {
			return new WP_Error(
				'upload_error',
				$upload['error'],
				array( 'status' => 500 )
			);
		}

		// Create attachment.
		$attachment_id = wp_insert_attachment(
			array(
				'post_mime_type' => $upload['type'],
				'post_title'     => sanitize_file_name( $file['name'] ),
				'post_content'   => '',
				'post_status'    => 'inherit',
			),
			$upload['file']
		);

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

		// Generate metadata.
		$attach_data = wp_generate_attachment_metadata( $attachment_id, $upload['file'] );
		wp_update_attachment_metadata( $attachment_id, $attach_data );

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => array(
					'id'   => $attachment_id,
					'url'  => $upload['url'],
					'type' => $upload['type'],
					'name' => basename( $upload['file'] ),
				),
			)
		);
	}

	/**
	 * Resolve product name for upload filename generation.
	 *
	 * If product name is missing, derive it from WooCommerce product ID.
	 *
	 * @param int    $product_id  Product ID.
	 * @param string $product_name Product name from request.
	 * @return string
	 */
	private function resolve_product_name_for_upload( int $product_id, string $product_name ): string {
		$normalized_name = sanitize_text_field( $product_name );
		if ( '' !== $normalized_name ) {
			return $normalized_name;
		}

		if ( $product_id > 0 && function_exists( 'wc_get_product' ) ) {
			$product = wc_get_product( $product_id );
			if ( $product && is_object( $product ) && method_exists( $product, 'get_name' ) ) {
				$resolved_name = sanitize_text_field( (string) $product->get_name() );
				if ( '' !== $resolved_name ) {
					return $resolved_name;
				}
			}
		}

		return 'product';
	}

	/**
	 * Resolve S3 date folder from original review submission date.
	 *
	 * @param int $review_id Review ID.
	 * @return string Valid Y-m-d or empty.
	 */
	private function resolve_review_date_folder_for_upload( int $review_id ): string {
		if ( $review_id <= 0 ) {
			return '';
		}

		global $wpdb;
		$table_name = $wpdb->prefix . 'ugcify_reviews';
		$created_at = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT created_at FROM {$table_name} WHERE id = %d LIMIT 1",
				$review_id
			)
		);

		if ( empty( $created_at ) || ! is_string( $created_at ) ) {
			return '';
		}

		$date = \DateTime::createFromFormat( 'Y-m-d H:i:s', $created_at, wp_timezone() );
		if ( $date instanceof \DateTimeInterface ) {
			return $date->format( 'Y-m-d' );
		}

		$timestamp = strtotime( $created_at );
		if ( false === $timestamp ) {
			return '';
		}

		return wp_date( 'Y-m-d', $timestamp, wp_timezone() );
	}

	/**
	 * Extract replaceable S3 object key from a source URL.
	 *
	 * Only returns keys inside configured path_prefix.
	 *
	 * @param StorageManager $storage Storage manager.
	 * @param string         $source_url Candidate source URL.
	 * @return string
	 */
	private function extract_replace_object_key_from_url( StorageManager $storage, string $source_url ): string {
		if ( '' === trim( $source_url ) ) {
			return '';
		}

		$settings = $storage->get_settings();
		$host     = (string) wp_parse_url( $source_url, PHP_URL_HOST );
		$path     = trim( (string) wp_parse_url( $source_url, PHP_URL_PATH ), '/' );
		if ( '' === $host || '' === $path ) {
			return '';
		}

		$bucket = (string) ( $settings['bucket'] ?? '' );
		if ( '' === $bucket ) {
			return '';
		}

		$key = '';
		if ( ! empty( $settings['custom_endpoint'] ) ) {
			$parts = explode( '/', $path, 2 );
			if ( count( $parts ) < 2 || $parts[0] !== $bucket ) {
				return '';
			}
			$key = $parts[1];
		} elseif ( false !== strpos( $host, $bucket . '.s3.' ) ) {
			$key = $path;
		} else {
			return '';
		}

		$key    = ltrim( $key, '/' );
		$prefix = trim( (string) ( $settings['path_prefix'] ?? '' ), '/' );
		if ( '' !== $prefix && 0 !== strpos( $key, $prefix . '/' ) ) {
			return '';
		}

		return $key;
	}

	/**
	 * Create review
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function create_review( $request ) {
		global $wpdb;

		$params = $request->get_json_params();

		// Verify reCAPTCHA if enabled.
		$settings = get_option( 'ugcify_review_form_settings', array() );
		if ( ! empty( $settings['recaptchaEnabled'] ) && ! empty( $settings['recaptchaSecretKey'] ) ) {
			$recaptcha_token = isset( $params['recaptcha_token'] ) ? $params['recaptcha_token'] : '';

			if ( empty( $recaptcha_token ) ) {
				return new WP_Error(
					'recaptcha_missing',
					__( 'reCAPTCHA verification is required.', 'ugcify' ),
					array( 'status' => 400 )
				);
			}

			// Verify reCAPTCHA token with Google.
			$verify_url = 'https://www.google.com/recaptcha/api/siteverify';
			$verify_data = array(
				'secret'   => $settings['recaptchaSecretKey'],
				'response' => $recaptcha_token,
				'remoteip' => sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? '' ) ),
			);

			$verify_response = wp_remote_post( $verify_url, array(
				'body' => $verify_data,
			) );

			if ( is_wp_error( $verify_response ) ) {
				return new WP_Error(
					'recaptcha_verification_failed',
					__( 'reCAPTCHA verification failed. Please try again.', 'ugcify' ),
					array( 'status' => 500 )
				);
			}

			$verify_result = json_decode( wp_remote_retrieve_body( $verify_response ), true );

			if ( empty( $verify_result['success'] ) ) {
				return new WP_Error(
					'recaptcha_invalid',
					__( 'reCAPTCHA verification failed. Please try again.', 'ugcify' ),
					array( 'status' => 400 )
				);
			}
		}

		// Validate required fields.
		$required_fields = array( 'rating', 'email', 'displayName', 'message', 'productId' );
		foreach ( $required_fields as $field ) {
			if ( empty( $params[ $field ] ) ) {
				return new WP_Error(
					'missing_field',
					sprintf(
						/* translators: %s: field name */
						__( 'Missing required field: %s', 'ugcify' ),
						$field
					),
					array( 'status' => 400 )
				);
			}
		}

		// Validate rating.
		$rating = intval( $params['rating'] );
		if ( $rating < 1 || $rating > 5 ) {
			return new WP_Error(
				'invalid_rating',
				__( 'Rating must be between 1 and 5.', 'ugcify' ),
				array( 'status' => 400 )
			);
		}

		// Validate email.
		$email = sanitize_email( $params['email'] );
		if ( ! is_email( $email ) ) {
			return new WP_Error(
				'invalid_email',
				__( 'Invalid email address.', 'ugcify' ),
				array( 'status' => 400 )
			);
		}

		// Check if verified buyer requirement.
		$settings   = get_option( 'ugcify_review_form_settings', array() );
		$visibility = isset( $settings['formVisibility'] ) ? $settings['formVisibility'] : 'logged-in';

		if ( 'verified-buyers' === $visibility && function_exists( 'wc_customer_bought_product' ) ) {
			$current_user = wp_get_current_user();
			if ( ! wc_customer_bought_product( $email, $current_user->ID, intval( $params['productId'] ) ) ) {
				return new WP_Error(
					'not_verified_buyer',
					__( 'Only verified buyers can submit reviews for this product.', 'ugcify' ),
					array( 'status' => 403 )
				);
			}
		}

		$rate_limit_config = $this->get_review_frequency_limit_config( $settings );
		if ( ! empty( $rate_limit_config['enabled'] ) ) {
			$product_id       = isset( $params['productId'] ) ? absint( $params['productId'] ) : 0;
			$rate_limit_check = $this->validate_review_submission_frequency( $rate_limit_config, $product_id );
			if ( is_wp_error( $rate_limit_check ) ) {
				return $rate_limit_check;
			}
		}

		// Prepare review data.
		$table_name = $wpdb->prefix . 'ugcify_reviews';

		$review_data = array(
			'product_id'   => intval( $params['productId'] ),
			'user_id'      => is_user_logged_in() ? get_current_user_id() : 0,
			'rating'       => $rating,
			'title'        => '',
			'content'      => wp_kses_post( $params['message'] ),
			'author_name'  => isset( $params['anonymous'] ) && $params['anonymous'] ? __( 'Anonymous', 'ugcify' ) : sanitize_text_field( $params['displayName'] ),
			'author_email' => $email,
			'status'       => 'pending',
			'created_at'   => current_time( 'mysql' ),
		);

		// Insert review.
		$inserted = $wpdb->insert( $table_name, $review_data );

		if ( false === $inserted ) {
			return new WP_Error(
				'insert_failed',
				__( 'Failed to save review.', 'ugcify' ),
				array( 'status' => 500 )
			);
		}

		$review_id = $wpdb->insert_id;

		// Save media attachments if provided.
		if ( ! empty( $params['images'] ) || ! empty( $params['videos'] ) ) {
			$media_table = $wpdb->prefix . 'ugcify_review_media';

			$all_media = array_merge(
				! empty( $params['images'] ) ? $params['images'] : array(),
				! empty( $params['videos'] ) ? $params['videos'] : array()
			);

			foreach ( $all_media as $media ) {
				if ( isset( $media['id'] ) ) {
					$wpdb->insert(
						$media_table,
						array(
							'review_id'     => $review_id,
							'attachment_id' => intval( $media['id'] ),
							'media_type'    => strpos( $media['type'], 'video' ) !== false ? 'video' : 'image',
							'media_url'     => esc_url_raw( $media['url'] ),
							'created_at'    => current_time( 'mysql' ),
						)
					);
				}
			}
		}

		// Save metadata if anonymous.
		$meta_table = $wpdb->prefix . 'ugcify_review_meta';
		if ( ! is_user_logged_in() ) {
			$client_ip = $this->get_client_ip_address();
			if ( ! empty( $client_ip ) ) {
				$wpdb->insert(
					$meta_table,
					array(
						'review_id'  => $review_id,
						'meta_key'   => 'submission_ip',
						'meta_value' => $client_ip,
					)
				);
			}
		}

		if ( isset( $params['anonymous'] ) && $params['anonymous'] ) {
			$wpdb->insert(
				$meta_table,
				array(
					'review_id'  => $review_id,
					'meta_key'   => 'is_anonymous',
					'meta_value' => '1',
				)
			);
		}

		// Set contributor type if user is an influencer AND the Creator Portal feature is enabled
		// AND the review was explicitly submitted from the portal (not the normal review form).
		// The from_portal flag is set by the frontend only when the button lives inside the portal page.
		if (
			! empty( $params['from_portal'] ) &&
			is_user_logged_in() &&
			class_exists( '\\Ugcify\\Influencer\\Settings' ) &&
			\Ugcify\Influencer\Settings::is_enabled()
		) {
			$user_repository = new \Ugcify\Database\UserRepository();
			if ( $user_repository->is_creator( get_current_user_id() ) ) {
				$wpdb->insert(
					$meta_table,
					array(
						'review_id'  => $review_id,
						'meta_key'   => '_ugcify_contributor_type',
						'meta_value' => 'influencer',
					)
				);
			}
		}

		// Fire review submitted action for email triggers.
		do_action( 'ugcify_review_submitted', $review_id, $review_data );

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => __( 'Review submitted successfully!', 'ugcify' ),
				'data'    => array(
					'review_id' => $review_id,
					'status'    => 'pending',
				),
			)
		);
	}

	/**
	 * Build rate limit config from settings.
	 *
	 * @param array $settings Review form settings.
	 * @return array
	 */
	private function get_review_frequency_limit_config( $settings ) {
		$enabled        = ! empty( $settings['enableReviewFrequencyLimit'] );
		$window_value   = isset( $settings['reviewLimitFrequencyValue'] ) ? absint( $settings['reviewLimitFrequencyValue'] ) : 1;
		$window_unit    = isset( $settings['reviewLimitFrequencyUnit'] ) ? sanitize_key( $settings['reviewLimitFrequencyUnit'] ) : 'hour';
		$max_submissions = isset( $settings['maxReviewsPerFrequency'] ) ? absint( $settings['maxReviewsPerFrequency'] ) : 3;

		if ( $window_value < 1 ) {
			$window_value = 1;
		}
		if ( ! in_array( $window_unit, array( 'minute', 'hour', 'day' ), true ) ) {
			$window_unit = 'hour';
		}
		if ( $max_submissions < 1 ) {
			$max_submissions = 1;
		}

		return array(
			'enabled'         => $enabled,
			'window_value'    => $window_value,
			'window_unit'     => $window_unit,
			'max_submissions' => $max_submissions,
		);
	}

	/**
	 * Validate submission frequency limit by user id (logged in) or IP (guest).
	 *
	 * @param array $config Rate limit config.
	 * @return true|WP_Error
	 */
	private function validate_review_submission_frequency( $config, $product_id = 0 ) {
		global $wpdb;

		$window_seconds  = $this->get_rate_window_seconds( $config['window_value'], $config['window_unit'] );
		$now_dt          = new \DateTime( 'now', wp_timezone() );
		$window_start_dt = clone $now_dt;
		$window_start_dt->modify( '-' . $window_seconds . ' seconds' );
		$window_start    = $window_start_dt->format( 'Y-m-d H:i:s' );
		$table_reviews  = $wpdb->prefix . 'ugcify_reviews';

		$product_id = absint( $product_id );
		if ( $product_id < 1 ) {
			return true;
		}

		if ( is_user_logged_in() ) {
			$user_id = get_current_user_id();
			$review_count = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$table_reviews} WHERE user_id = %d AND product_id = %d AND created_at >= %s",
					$user_id,
					$product_id,
					$window_start
				)
			);
		} else {
			$client_ip = $this->get_client_ip_address();
			if ( empty( $client_ip ) ) {
				$client_ip = 'unknown';
			}

			$table_meta = $wpdb->prefix . 'ugcify_review_meta';
			$review_count = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) 
					FROM {$table_reviews} r
					INNER JOIN {$table_meta} m ON m.review_id = r.id
					WHERE m.meta_key = %s
					AND m.meta_value = %s
					AND r.product_id = %d
					AND r.created_at >= %s",
					'submission_ip',
					$client_ip,
					$product_id,
					$window_start
				)
			);
		}

		if ( $review_count >= $config['max_submissions'] ) {
			$unit_label = $this->get_frequency_unit_label( $config['window_unit'] );
			return new WP_Error(
				'review_submission_rate_limited',
				sprintf(
					/* translators: 1: max reviews, 2: frequency value, 3: frequency unit. */
					__( 'You can only submit %1$d review(s) per %2$d %3$s. Please try again later.', 'ugcify' ),
					$config['max_submissions'],
					$config['window_value'],
					$unit_label
				),
				array( 'status' => 429 )
			);
		}

		return true;
	}

	/**
	 * Resolve rate limit window in seconds.
	 *
	 * @param int    $value Window value.
	 * @param string $unit Window unit.
	 * @return int
	 */
	private function get_rate_window_seconds( $value, $unit ) {
		$sanitized_value = max( 1, (int) $value );

		switch ( $unit ) {
			case 'day':
				return $sanitized_value * DAY_IN_SECONDS;
			case 'hour':
				return $sanitized_value * HOUR_IN_SECONDS;
			case 'minute':
			default:
				return $sanitized_value * MINUTE_IN_SECONDS;
		}
	}

	/**
	 * Resolve frequency unit display label.
	 *
	 * @param string $unit Frequency unit.
	 * @return string
	 */
	private function get_frequency_unit_label( $unit ) {
		switch ( $unit ) {
			case 'day':
				return __( 'day(s)', 'ugcify' );
			case 'hour':
				return __( 'hour(s)', 'ugcify' );
			case 'minute':
			default:
				return __( 'minute(s)', 'ugcify' );
		}
	}

	/**
	 * Get client IP address.
	 *
	 * @return string
	 */
	private function get_client_ip_address() {
		$ip_sources = array(
			'HTTP_CF_CONNECTING_IP',
			'HTTP_X_FORWARDED_FOR',
			'HTTP_X_REAL_IP',
			'REMOTE_ADDR',
		);

		foreach ( $ip_sources as $source ) {
			if ( empty( $_SERVER[ $source ] ) ) {
				continue;
			}

			$candidate = sanitize_text_field( wp_unslash( $_SERVER[ $source ] ) );
			$parts     = explode( ',', (string) $candidate );
			$ip        = trim( $parts[0] );

			if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
				return $ip;
			}
		}

		return '';
	}

	/**
	 * Get review schema
	 *
	 * @return array
	 */
	private function get_review_schema() {
		return array(
			'productId'   => array(
				'type'        => 'integer',
				'required'    => true,
				'description' => __( 'Product ID', 'ugcify' ),
			),
			'rating'      => array(
				'type'        => 'integer',
				'required'    => true,
				'minimum'     => 1,
				'maximum'     => 5,
				'description' => __( 'Rating (1-5)', 'ugcify' ),
			),
			'email'       => array(
				'type'        => 'string',
				'format'      => 'email',
				'required'    => true,
				'description' => __( 'Email address', 'ugcify' ),
			),
			'displayName' => array(
				'type'        => 'string',
				'required'    => true,
				'description' => __( 'Display name', 'ugcify' ),
			),
			'message'     => array(
				'type'        => 'string',
				'required'    => true,
				'description' => __( 'Review message', 'ugcify' ),
			),
			'anonymous'   => array(
				'type'        => 'boolean',
				'required'    => false,
				'description' => __( 'Post as anonymous', 'ugcify' ),
			),
			'images'      => array(
				'type'        => 'array',
				'required'    => false,
				'description' => __( 'Uploaded images', 'ugcify' ),
			),
			'videos'      => array(
				'type'        => 'array',
				'required'    => false,
				'description' => __( 'Uploaded videos', 'ugcify' ),
			),
		);
	}
}
