<?php

namespace WC_Affiliate\Controllers\Common;

defined( 'ABSPATH' ) || exit;

use WC_Affiliate\API\Affiliate as AffiliateAPI;
use WC_Affiliate\API\Dashboard as DashboardAPI;
use WC_Affiliate\API\Export as ExportAPI;
use WC_Affiliate\API\Import as ImportAPI;
use WC_Affiliate\API\Notices as NoticesAPI;
use WC_Affiliate\API\Referral as ReferralAPI;
use WC_Affiliate\API\Settings as SettingsAPI;
use WC_Affiliate\API\Transaction as TransactionAPI;
use WC_Affiliate\API\Visit as VisitAPI;
use WC_Affiliate\Models\Affiliate;
use WP_Error;
use WP_REST_Request;
use WP_REST_Server;

/**
 * REST API Controller for WC Affiliate Plugin.
 *
 * Handles registration and management of all REST API endpoints for the affiliate system,
 * including affiliates, visits, referrals, transactions, and administrative operations.
 *
 * @since 1.0.0
 */
class API {

	/**
	 * API version
	 */
	const API_VERSION = 'v1';

	/**
	 * API namespace
	 */
	const API_NAMESPACE = 'wc-affiliate/' . self::API_VERSION;

	/**
	 * Controller constructor
	 *
	 * Initializes the REST API controller and registers necessary hooks
	 */
	public function __construct() {
		$this->register_hooks();
	}

	/**
	 * Register hooks for API controller
	 *
	 * @return void
	 */
	protected function register_hooks(): void {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
		add_action( 'wp_ajax_wc_affiliate_download_export', array( $this, 'handle_download_export' ) );
		add_action( 'wp_ajax_nopriv_wc_affiliate_download_export', array( $this, 'handle_download_export' ) );
	}

	/**
	 * Register all API routes
	 *
	 * Registers all REST API endpoints for the WC Affiliate plugin including
	 * dashboard, affiliates, users, visits, referrals, transactions, and more.
	 *
	 * @return void
	 */
	public function register_routes(): void {
		/**
		 * Action hook fired before API routes registration.
		 */
		do_action( 'wc_affiliate_api_register_routes_before' );

		// Register API endpoints.
		$this->register_dashboard_routes();
		$this->register_affiliate_routes();
		$this->register_user_routes();
		$this->register_visit_routes();
		$this->register_referral_routes();
		$this->register_transaction_routes();
		$this->register_wizard_routes();
		$this->register_export_routes();
		$this->register_import_routes();
		$this->register_settings_routes();
		$this->register_notices_routes();

		/**
		 * Action hook fired after API routes registration.
		 */
		do_action( 'wc_affiliate_api_register_routes_after' );
	}

	public function handle_download_export() {
		$export_api = new ExportAPI();
		$export_api->handle_download_export();
	}

	/**
	 * Get reusable period argument schema for API endpoints.
	 *
	 * @return array Period argument schema with all supported time periods.
	 */
	protected function get_period_arg_schema(): array {
		return array(
			'description' => esc_html__( 'Time period for data filtering.', 'wc-affiliate' ),
			'type'        => 'string',
			'enum'        => array( 'all_time', 'today', 'this_week', 'last_7_days', 'last_14_days', 'last_30_days', 'last_90_days', 'this_month', 'last_month', 'this_year', 'last_year', 'custom' ),
			'default'     => 'last_30_days',
		);
	}

	/**
	 * Register dashboard API routes.
	 *
	 * Registers REST API endpoints for dashboard functionality including:
	 * - Dashboard overview statistics
	 * - Dashboard chart data
	 * - Top performers data
	 *
	 * @since 1.0.0
	 * @return void
	 */
	protected function register_dashboard_routes() {
		$dashboard_api = new DashboardAPI();

		// Dashboard overview stats.
		register_rest_route(
			self::API_NAMESPACE,
			'/dashboard/stats',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $dashboard_api, 'get_stats' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_dashboard_stats_args',
					array(
						'period'     => $this->get_period_arg_schema(),
						'start_date' => array(
							'description' => esc_html__( 'Start date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'   => array(
							'description' => esc_html__( 'End date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
					)
				),
			)
		);

		// Dashboard chart data.
		register_rest_route(
			self::API_NAMESPACE,
			'/dashboard/charts',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $dashboard_api, 'get_charts' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_dashboard_charts_args',
					array(
						'chart_type'   => array(
							'description' => esc_html__( 'Type of chart data to retrieve: visits, referrals, commissions, conversions.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'visits', 'referrals', 'commissions', 'conversions' ),
							'required'    => true,
						),
						'period'       => $this->get_period_arg_schema(),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'affiliate_id' => array(
							'description' => esc_html__( 'Affiliate ID to filter chart data by. Default is 0 (all affiliates).', 'wc-affiliate' ),
							'type'        => 'integer',
							'minimum'     => 0,
							'default'     => 0,
							'required'    => false,
						),
					)
				),
			)
		);

		// Get top performers.
		register_rest_route(
			self::API_NAMESPACE,
			'/dashboard/top-performers',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $dashboard_api, 'get_top_performers' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_dashboard_top_performers_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'Affiliate ID to filter data for specific affiliate. If not provided, returns admin data.', 'wc-affiliate' ),
							'type'        => 'integer',
							'minimum'     => 1,
						),
						'type'         => array(
							'description' => esc_html__( 'Type of top performers to retrieve: affiliates, products, pages, referrers.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'affiliates', 'products', 'pages', 'referrers' ),
							'required'    => true,
						),
						'period'       => $this->get_period_arg_schema(),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'limit'        => array(
							'description' => esc_html__( 'Maximum number of top performers to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 10,
							'minimum'     => 5,
							'maximum'     => 50,
						),
					)
				),
			)
		);
	}

	/**
	 * Register affiliate routes
	 */
	protected function register_affiliate_routes() {
		/**
		 * Action hook fired before affiliate routes registration.
		 */
		do_action( 'wc_affiliate_api_register_affiliate_routes_before' );

		$affiliate_api = new AffiliateAPI();

		// Get affiliates list.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'list' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_list_args',
					array(
						'page'     => array(
							'description' => esc_html__( 'Current page number for pagination.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
							'minimum'     => 1,
						),
						'per_page' => array(
							'description' => esc_html__( 'Number of affiliates to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 20,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'status'   => array(
							'description' => esc_html__( 'Filter affiliates by status: active, pending, rejected, suspended.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array_merge( array_keys( wca_get_affiliate_statuses() ), array( 'all' ) ),
							'default'     => 'all',
						),
						'search'   => array(
							'description' => esc_html__( 'Search term to filter affiliates by name or email.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'orderby'  => array(
							'description' => esc_html__( 'Field to order affiliates by: user_registered, user_login, display_name, ID.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'user_registered', 'user_login', 'display_name', 'ID' ),
							'default'     => 'user_registered',
						),
						'order'    => array(
							'description' => esc_html__( 'Order direction: ASC or DESC.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'ASC', 'DESC' ),
							'default'     => 'DESC',
						),
					)
				),
			)
		);

		// Create affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'create' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_create_args',
					array(
						'user_id'           => array(
							'description' => esc_html__( 'ID of the user to create as an affiliate.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'commission_type'   => array(
							'description' => esc_html__( 'Commission type: fixed, percent, or default. When set to "default", the global commission settings will be applied. The default value is "default".', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array_merge( array_keys( wca_get_commission_types() ), array( 'default' ) ),
							'required'    => false,
							'default'     => 'default',
						),
						'commission_amount' => array(
							'description' => esc_html__( 'Amount of the commission rate or fixed value.', 'wc-affiliate' ),
							'type'        => 'number',
							'minimum'     => 0,
						),
						'status'            => array(
							'description' => esc_html__( 'Initial status of the affiliate: active, pending, rejected, suspended.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array_keys( wca_get_affiliate_statuses() ),
							'default'     => 'pending',
						),
					)
				),
			)
		);

		// Get single affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_get_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Update affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $affiliate_api, 'update' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_update_args',
					array(
						'affiliate_id'      => array(
							'description' => esc_html__( 'ID of the affiliate to update.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'status'            => array(
							'description' => esc_html__( 'New status for the affiliate: active, pending, rejected, suspended.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array_keys( wca_get_affiliate_statuses() ),
						),
						'commission_type'   => array(
							'description' => esc_html__( 'Updated commission type: fixed or percent.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array_keys( wca_get_commission_types() ),
						),
						'commission_amount' => array(
							'description' => esc_html__( 'Updated commission amount.', 'wc-affiliate' ),
							'type'        => 'number',
							'minimum'     => 0,
						),
						'payment_method'    => array(
							'description' => esc_html__( 'Preferred payment method for the affiliate.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'payment_details'   => array(
							'description' => esc_html__( 'Additional payment details, such as PayPal email or bank info.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'auto_payout'       => array(
							'description' => esc_html__( 'Whether to enable automatic payouts for the affiliate.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Delete affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)',
			array(
				'methods'             => WP_REST_Server::DELETABLE,
				'callback'            => array( $affiliate_api, 'delete' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_delete_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to delete.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Get affiliate statistics.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/stats',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_stats' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_stats_args',
					array(
						'period'     => $this->get_period_arg_schema(),
						'start_date' => array(
							'description' => esc_html__( 'Start date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'   => array(
							'description' => esc_html__( 'End date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
					)
				),
			)
		);

		// Get my affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/me',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'me' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);

		// Apply for affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/apply',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'apply' ),
				'permission_callback' => '__return_true',
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_apply_args',
					array(
						// User registration fields (for new users).
						'first_name'         => array(
							'description'       => esc_html__( 'User first name.', 'wc-affiliate' ),
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'last_name'          => array(
							'description'       => esc_html__( 'User last name.', 'wc-affiliate' ),
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'user_login'         => array(
							'description'       => esc_html__( 'User login name.', 'wc-affiliate' ),
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'email'              => array(
							'description'       => esc_html__( 'User email address.', 'wc-affiliate' ),
							'type'              => 'string',
							'format'            => 'email',
							'required'          => false,
							'sanitize_callback' => 'sanitize_email',
						),
						'user_password'      => array(
							'description' => esc_html__( 'User password.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
						'user_password2'     => array(
							'description' => esc_html__( 'Password confirmation.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),

						// Affiliate application fields.
						'website_url'        => array(
							'description'       => esc_html__( 'Affiliate website URL.', 'wc-affiliate' ),
							'type'              => 'string',
							'format'            => 'uri',
							'required'          => false,
							'sanitize_callback' => 'esc_url_raw',
						),
						'terms_agree'        => array(
							'description' => esc_html__( 'Terms and conditions agreement.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
						'recaptcha_response' => array(
							'description' => esc_html__( 'reCAPTCHA response token.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
						'promotion_method'   => array(
							'description'       => esc_html__( 'How the affiliate plans to promote.', 'wc-affiliate' ),
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_textarea_field',
						),
						'commission_type'    => array(
							'description' => esc_html__( 'Commission type: fixed, percent, or default. When set to "default", the global commission settings will be applied. The default value is "default".', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array_merge( array_keys( wca_get_commission_types() ), array( 'default' ) ),
							'required'    => false,
							'default'     => 'default',
						),
						'commission_amount'  => array(
							'description' => esc_html__( 'Commission amount.', 'wc-affiliate' ),
							'type'        => 'number',
							'minimum'     => 0,
							'required'    => false,
						),

						// Legacy field for backward compatibility.
						'description'        => array(
							'description'       => esc_html__( 'Description of why the user wants to become an affiliate.', 'wc-affiliate' ),
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_textarea_field',
						),
					)
				),
			)
		);

		// Generate affiliate link.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/generate-link',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'generate_link' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_generate_link_args',
					array(
						'page_url' => array(
							'description' => esc_html__( 'URL of the page to generate the affiliate link for.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'format'      => 'uri',
						),
						'campaign' => array(
							'description' => esc_html__( 'Campaign identifier for tracking the link.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Get leaderboard.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/leaderboard',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_leaderboard' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_leaderboard_args',
					array(
						'period'     => array(
							'description' => esc_html__( 'Time period for the leaderboard: week, month, quarter, year, all_time, today.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'week', 'month', 'quarter', 'year', 'all_time', 'today' ),
							'default'     => 'month',
						),
						'start_date' => array(
							'description' => esc_html__( 'Start date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'   => array(
							'description' => esc_html__( 'End date for custom period in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'limit'      => array(
							'description' => esc_html__( 'Maximum number of affiliates to show in the leaderboard.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 10,
							'minimum'     => 5,
							'maximum'     => 50,
						),
						'order_by'   => array(
							'description' => esc_html__( 'Metric to rank affiliates by: commissions, referrals, visits.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'commissions', 'referrals', 'visits' ),
							'default'     => 'commissions',
						),
					)
				),
			)
		);

		// Update bulk affiliate status.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/bulk/status',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $affiliate_api, 'bulk_update_status' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_bulk_status_args',
					array(
						'ids'    => array(
							'description' => esc_html__( 'Array of affiliate IDs to update status for.', 'wc-affiliate' ),
							'type'        => 'array',
							'required'    => true,
							'items'       => array( 'type' => 'integer' ),
						),
						'status' => array(
							'description' => esc_html__( 'New status to apply to the selected affiliates: active, pending, rejected, suspended.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array_keys( wca_get_affiliate_statuses() ),
						),
					)
				),
			)
		);

		// Get affiliate status counts.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/status-counts',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_status_counts' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_status_counts_args',
					array(
						'start_date' => array(
							'description' => esc_html__( 'Start date for filtering status counts in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'   => array(
							'description' => esc_html__( 'End date for filtering status counts in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
					)
				),
			)
		);

		// Remove affiliate status.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/remove',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'remove_affiliate' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_remove_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to remove.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Review affiliate application (approve/reject).
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/review',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'review_application' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_review_args',
					array(
						'action'  => array(
							'description' => esc_html__( 'Review action: approve or reject.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array( 'approve', 'reject' ),
						),
						'message' => array(
							'description' => esc_html__( 'Optional message to send to the affiliate.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Get recent referrals for affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/recent-referrals',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_recent_referrals' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_recent_referrals_args',
					array(
						'limit' => array(
							'description' => esc_html__( 'Maximum number of recent referrals to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'minimum'     => 1,
							'maximum'     => 20,
							'default'     => 5,
						),
					)
				),
			)
		);

		// Get recent visits for affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/recent-visits',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_recent_visits' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_recent_visits_args',
					array(
						'limit' => array(
							'description' => esc_html__( 'Maximum number of recent visits to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'minimum'     => 1,
							'maximum'     => 50,
							'default'     => 10,
						),
					)
				),
			)
		);

		// Get recent activities for affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/(?P<affiliate_id>\d+)/recent-activities',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_recent_activities' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_recent_activities_args',
					array(
						'limit' => array(
							'description' => esc_html__( 'Maximum number of recent activities to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'minimum'     => 1,
							'maximum'     => 50,
							'default'     => 20,
						),
					)
				),
			)
		);

		// Get referred affiliates for current user.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/me/referred',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $affiliate_api, 'get_referred_affiliates' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);

		// Handle affiliation assignment.
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/assign',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'handle_affiliation_assignment' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_affiliates_assign_args',
					array(
						'affiliate'         => array(
							'description' => esc_html__( 'ID of existing affiliate user.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'status'            => array(
							'description' => esc_html__( 'Affiliate status.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'commission_type'   => array(
							'description' => esc_html__( 'Commission type: fixed or percent.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'commission_amount' => array(
							'description' => esc_html__( 'Commission amount.', 'wc-affiliate' ),
							'type'        => 'number',
						),
						'first_name'        => array(
							'description' => esc_html__( 'First name for new user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'last_name'         => array(
							'description' => esc_html__( 'Last name for new user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'email'             => array(
							'description' => esc_html__( 'Email address for new user.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'email',
						),
						'password'          => array(
							'description' => esc_html__( 'Password for new user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'nonce'             => array(
							'description' => esc_html__( 'WordPress nonce for security.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Request payout (for affiliates).
		register_rest_route(
			self::API_NAMESPACE,
			'/affiliates/request-payout',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $affiliate_api, 'request_payout' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_transactions_request_payout_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate requesting the payout.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);
	}

	/**
	 * Register visit routes
	 */
	protected function register_visit_routes() {
		$visit_api = new VisitAPI();

		// Get visits.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'list' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_list_args',
					array(
						'affiliate_id'   => array(
							'description' => esc_html__( 'ID of the affiliate to filter visits for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'page'           => array(
							'description' => esc_html__( 'Current page number for pagination.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
							'minimum'     => 1,
						),
						'per_page'       => array(
							'description' => esc_html__( 'Number of visits to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 20,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'start_date'     => array(
							'description' => esc_html__( 'Start date for filtering visits in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'       => array(
							'description' => esc_html__( 'End date for filtering visits in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'converted_only' => array(
							'description' => esc_html__( 'Whether to return only visits that led to conversions.', 'wc-affiliate' ),
							'type'        => 'boolean',
							'default'     => false,
						),
						'campaign'       => array(
							'description' => esc_html__( 'Campaign identifier to filter visits by.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Track visit.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $visit_api, 'track_visit' ),
				'permission_callback' => '__return_true',
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_create_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate tracking the visit.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'page_url'     => array(
							'description' => esc_html__( 'URL of the page being visited.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'format'      => 'uri',
						),
						'referrer_url' => array(
							'description' => esc_html__( 'URL of the referring site or page.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'uri',
						),
						'campaign'     => array(
							'description' => esc_html__( 'Campaign identifier for the visit.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Get single visit.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/(?P<visit_id>\d+)',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'get_visit' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_get_args',
					array(
						'visit_id' => array(
							'description' => esc_html__( 'ID of the visit to retrieve.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Delete visit.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/(?P<visit_id>\d+)',
			array(
				'methods'             => WP_REST_Server::DELETABLE,
				'callback'            => array( $visit_api, 'delete_visit' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_delete_args',
					array(
						'visit_id' => array(
							'description' => esc_html__( 'ID of the visit to delete.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Get visit statistics.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/stats',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'get_visit_stats' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_stats_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve visit statistics for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'period'       => $this->get_period_arg_schema(),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for statistics in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for statistics in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
					)
				),
			)
		);

		// Get top pages.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/top-pages',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'get_top_pages' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_top_pages_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve top pages for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'limit'        => array(
							'description' => esc_html__( 'Maximum number of top pages to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 10,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'days'         => array(
							'description' => esc_html__( 'Number of days back to consider for top pages.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 30,
							'minimum'     => 1,
							'maximum'     => 365,
						),
					)
				),
			)
		);

		// Get top referrers.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/top-referrers',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'get_top_referrers' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_top_referrers_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve top referrers for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'limit'        => array(
							'description' => esc_html__( 'Maximum number of top referrers to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 10,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'days'         => array(
							'description' => esc_html__( 'Number of days back to consider for top referrers.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 30,
							'minimum'     => 1,
							'maximum'     => 365,
						),
					)
				),
			)
		);

		// Get visit trends.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/trends',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'get_visit_trends' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_trends_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve visit trends for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'period'       => $this->get_period_arg_schema(),
						'start_date'   => array(
							'description' => esc_html__( 'Custom start date for trends in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'Custom end date for trends in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'group_by'     => array(
							'description' => esc_html__( 'Grouping interval for trends: day, week, month.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'day', 'week', 'month' ),
							'default'     => 'day',
						),
					)
				),
			)
		);

		// Clean up old visits (admin only).
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/cleanup',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $visit_api, 'cleanup_visits' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_cleanup_args',
					array(
						'days' => array(
							'description' => esc_html__( 'Number of days to retain visits; older ones will be deleted.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 30,
							'minimum'     => 30,
							'maximum'     => 365,
						),
					)
				),
			)
		);

		// Get visit conversion counts.
		register_rest_route(
			self::API_NAMESPACE,
			'/visits/conversion-counts',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $visit_api, 'get_conversion_counts' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_visits_conversion_counts_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve conversion counts for.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => false,
						),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for conversion counts in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for conversion counts in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'campaign'     => array(
							'description' => esc_html__( 'Campaign identifier to filter conversion counts by.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);
	}

	/**
	 * Register referral routes
	 */
	protected function register_referral_routes() {
		$referral_api = new ReferralAPI();

		// Get referrals list.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'list' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_list_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to filter referrals for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'status'       => array(
							'description' => esc_html__( 'Filter referrals by status: pending, paid, approved, rejected, cancelled.', 'wc-affiliate' ),
							'type'        => 'array',
							'default'     => array( 'pending', 'paid', 'approved', 'rejected', 'cancelled' ),
						),
						'page'         => array(
							'description' => esc_html__( 'Current page number for pagination.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
						),
						'per_page'     => array(
							'description' => esc_html__( 'Number of referrals to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 20,
							'maximum'     => 100,
						),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for filtering referrals in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for filtering referrals in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'order_id'     => array(
							'description' => esc_html__( 'Order ID to filter referrals by.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'product_id'   => array(
							'description' => esc_html__( 'Product ID to filter referrals by.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'search'       => array(
							'description' => esc_html__( 'Search term to filter referrals by affiliate name or product name.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'type'         => array(
							'description' => esc_html__( 'Type of referral: sale, recurring, signup, lead.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'sale', 'recurring', 'signup', 'lead' ),
						),
					)
				),
			)
		);

		// Create referral.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $referral_api, 'create' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_create_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate for the referral.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'order_id'     => array(
							'description' => esc_html__( 'ID of the order associated with the referral.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'commission'   => array(
							'description' => esc_html__( 'Commission amount earned from the referral.', 'wc-affiliate' ),
							'type'        => 'number',
							'required'    => true,
							'minimum'     => 0,
						),
						'order_total'  => array(
							'description' => esc_html__( 'Total amount of the order.', 'wc-affiliate' ),
							'type'        => 'number',
							'required'    => true,
							'minimum'     => 0,
						),
						'visit_id'     => array(
							'description' => esc_html__( 'ID of the visit that led to this referral.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'type'         => array(
							'description' => esc_html__( 'Type of referral: sale, recurring, signup, lead.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'sale', 'recurring', 'signup', 'lead' ),
						),
						'products'     => array(
							'description' => esc_html__( 'Array of products involved in the referral.', 'wc-affiliate' ),
							'type'        => 'object',
						),
					)
				),
			)
		);

		// Get single referral.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/(?P<referral_id>\d+)',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_get_args',
					array(
						'referral_id' => array(
							'description' => esc_html__( 'ID of the referral to retrieve.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Delete referral.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/(?P<referral_id>\d+)',
			array(
				'methods'             => WP_REST_Server::DELETABLE,
				'callback'            => array( $referral_api, 'delete' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_delete_args',
					array(
						'referral_id' => array(
							'description' => esc_html__( 'ID of the referral to delete.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Update referral status.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/(?P<referral_id>\d+)/status',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $referral_api, 'update_status' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_update_status_args',
					array(
						'referral_id' => array(
							'description' => esc_html__( 'ID of the referral to update status for.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'status'      => array(
							'description' => esc_html__( 'New status for the referral: pending, paid, approved, rejected, cancelled.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array( 'pending', 'paid', 'approved', 'rejected', 'cancelled' ),
						),
					)
				),
			)
		);

		// Bulk update referral status.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/bulk/status',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $referral_api, 'bulk_update_status' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_bulk_update_status_args',
					array(
						'ids'    => array(
							'description' => esc_html__( 'Array of referral IDs to update status for.', 'wc-affiliate' ),
							'type'        => 'array',
							'required'    => true,
							'items'       => array(
								'type' => 'integer',
							),
						),
						'status' => array(
							'description' => esc_html__( 'New status to apply to the selected referrals: pending, paid, approved, rejected, cancelled.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array( 'pending', 'paid', 'approved', 'rejected', 'cancelled' ),
						),
					)
				),
			)
		);

		// Get referral statistics.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/stats',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get_stats' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_stats_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve referral statistics for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'period'       => $this->get_period_arg_schema(),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for statistics in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for statistics in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
					)
				),
			)
		);

		// Get top products.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/top-products',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get_top_products' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_top_products_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve top products for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'limit'        => array(
							'description' => esc_html__( 'Maximum number of top products to return.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 10,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'days'         => array(
							'description' => esc_html__( 'Number of days back to consider for top products.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 30,
							'minimum'     => 1,
							'maximum'     => 365,
						),
					)
				),
			)
		);

		// Commission breakdown per referral id path.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/(?P<referral_id>\d+)/commission-breakdown',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get_commission_breakdown' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_commission_breakdown_args',
					array(
						'referral_id' => array(
							'description' => esc_html__( 'ID of the referral for commission breakdown.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Recalculate commission path id.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/(?P<referral_id>\d+)/recalculate',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $referral_api, 'recalculate_commission' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_recalculate_args',
					array(
						'referral_id' => array(
							'description' => esc_html__( 'ID of the referral to recalculate commission for.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Pending payouts extended params.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/pending-payouts',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get_pending_payouts' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_pending_payouts_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to retrieve pending payouts for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'min_amount'   => array(
							'description' => esc_html__( 'Minimum payout amount to consider.', 'wc-affiliate' ),
							'type'        => 'number',
							'minimum'     => 0,
						),
						'page'         => array(
							'description' => esc_html__( 'Current page number for pagination of pending payouts.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
						),
						'per_page'     => array(
							'description' => esc_html__( 'Number of pending payouts to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 50,
							'minimum'     => 1,
							'maximum'     => 100,
						),
					)
				),
			)
		);

		// Get payable affiliates with approved referrals.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/payable-affiliates',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get_approved_referrals_by_affiliate' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_payable_affiliates_args',
					array(
						'page'     => array(
							'description' => esc_html__( 'Current page number for pagination.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
							'minimum'     => 1,
						),
						'per_page' => array(
							'description' => esc_html__( 'Number of affiliates to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 50,
							'minimum'     => 10,
							'maximum'     => 100,
						),
					)
				),
			)
		);

		// Get referral status counts.
		register_rest_route(
			self::API_NAMESPACE,
			'/referrals/status-counts',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $referral_api, 'get_status_counts' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_referrals_status_counts_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to filter status counts for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'start_date'   => array(
							'description' => esc_html__( 'Start date for filtering status counts in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'     => array(
							'description' => esc_html__( 'End date for filtering status counts in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
					)
				),
			)
		);
	}

	/**
	 * Register transaction routes
	 */
	protected function register_transaction_routes() {
		$transaction_api = new TransactionAPI();

		// Get transactions.
		register_rest_route(
			self::API_NAMESPACE,
			'/transactions',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $transaction_api, 'list' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_transactions_list_args',
					array(
						'affiliate_id'   => array(
							'description' => esc_html__( 'ID of the affiliate to filter transactions for.', 'wc-affiliate' ),
							'type'        => 'integer',
						),
						'status'         => array(
							'description' => esc_html__( 'Filter transactions by status: pending, completed, failed, cancelled, processing.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'pending', 'completed', 'failed', 'cancelled', 'processing' ),
						),
						'payment_method' => array(
							'description' => esc_html__( 'Filter transactions by payment method: paypal, stripe, manual.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'paypal', 'stripe', 'manual' ),
						),
						'start_date'     => array(
							'description' => esc_html__( 'Start date for filtering transactions in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'end_date'       => array(
							'description' => esc_html__( 'End date for filtering transactions in YYYY-MM-DD format.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'date',
						),
						'txn_id'         => array(
							'description' => esc_html__( 'Transaction ID to filter by.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'page'           => array(
							'description' => esc_html__( 'Current page number for pagination.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
						),
						'per_page'       => array(
							'description' => esc_html__( 'Number of transactions to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 20,
						),
					)
				),
			)
		);

		// Process payout for affiliate.
		register_rest_route(
			self::API_NAMESPACE,
			'/transactions/payout',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $transaction_api, 'process_payout' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_transactions_payout_args',
					array(
						'referral_id'    => array(
							'description' => esc_html__( 'ID of the referral to process payout for.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'payment_method' => array(
							'description' => esc_html__( 'Payment method used for the transaction.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array_keys( wca_get_payment_methods_options() ),
						),
					)
				),
			)
		);

		// Mark transaction as paid.
		register_rest_route(
			self::API_NAMESPACE,
			'/transactions/mark-paid',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $transaction_api, 'mark_paid' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_transactions_mark_paid_args',
					array(
						'referral_id'    => array(
							'description' => esc_html__( 'ID of the referral to mark as paid.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'payment_method' => array(
							'description' => esc_html__( 'Payment method used for the transaction.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array_keys( wca_get_payment_methods_options() ),
						),
						'txn_id'         => array(
							'description' => esc_html__( 'External transaction ID.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Process affiliate payout.
		register_rest_route(
			self::API_NAMESPACE,
			'/transactions/affiliate-payout',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $transaction_api, 'process_affiliate_payout' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_transactions_affiliate_payout_args',
					array(
						'affiliate_id' => array(
							'description' => esc_html__( 'ID of the affiliate to process payout for.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
					)
				),
			)
		);

		// Mark affiliate as paid.
		register_rest_route(
			self::API_NAMESPACE,
			'/transactions/affiliate-mark-paid',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $transaction_api, 'mark_affiliate_paid' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_transactions_affiliate_mark_paid_args',
					array(
						'affiliate_id'   => array(
							'description' => esc_html__( 'ID of the affiliate to mark as paid.', 'wc-affiliate' ),
							'type'        => 'integer',
							'required'    => true,
						),
						'payment_method' => array(
							'description' => esc_html__( 'Payment method used for the transaction.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array_keys( wca_get_payment_methods_options() ),
						),
						'txn_id'         => array(
							'description' => esc_html__( 'External transaction ID.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);
	}

	/**
	 * Register setup-wizard routes
	 */
	protected function register_wizard_routes() {
		$wizard_api = new \WC_Affiliate\API\SetupWizard();

		// Get setup-wizard defaults.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/defaults',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $wizard_api, 'get_defaults' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_setup_wizard_defaults_args',
					array(
						'page' => array(
							'description' => esc_html__( 'Name of the setup-wizard page to retrieve defaults for.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Get setup-wizard configuration.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/config',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $wizard_api, 'get_config' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_setup_wizard_config_args',
					array(
						'page' => array(
							'description' => esc_html__( 'Name of the setup-wizard page to retrieve.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Get setup-wizard values.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/values',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $wizard_api, 'get_values' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_setup_wizard_values_args',
					array(
						'page' => array(
							'description' => esc_html__( 'Name of the setup-wizard page to retrieve values for.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Update setup-wizard settings.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/update',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $wizard_api, 'update' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_setup_wizard_update_args',
					array(
						'page'   => array(
							'description' => esc_html__( 'Name of the setup-wizard page to update.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
						'values' => array(
							'description' => esc_html__( 'page values to update.', 'wc-affiliate' ),
							'type'        => 'object',
							'required'    => true,
						),
					)
				),
			)
		);

		// Reset setup-wizard progress.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/reset',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $wizard_api, 'reset_wizard' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// Complete setup-wizard.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/complete',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $wizard_api, 'complete_wizard' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// Skip setup-wizard.
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/skip',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $wizard_api, 'skip_wizard' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_setup_wizard_skip_args',
					array(
						'skip_reason'        => array(
							'description' => esc_html__( 'Reason for skipping the setup wizard.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
						'additional_setting' => array(
							'description' => esc_html__( 'Additional setting when skipping wizard.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Install / activate a required platform plugin (e.g. WooCommerce).
		register_rest_route(
			self::API_NAMESPACE,
			'/setup-wizard/install-platform',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $wizard_api, 'install_platform' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_setup_wizard_install_platform_args',
					array(
						'plugin' => array(
							'description' => esc_html__( 'Plugin file path (e.g. woocommerce/woocommerce.php).', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
						'slug'   => array(
							'description' => esc_html__( 'Plugin slug on WordPress.org (e.g. woocommerce).', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);
	}

	/**
	 * Register export routes
	 */
	protected function register_export_routes() {
		$export_api = new ExportAPI();

		// Get available export types.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/types',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $export_api, 'get_types' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// Start export.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/start',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $export_api, 'start' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_export_start_args',
					array(
						'type'    => array(
							'description' => esc_html__( 'Type of data to export: affiliates, visits, referrals, payables, transactions, settings, complete.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array(
								'affiliates',
								'visits',
								'referrals',
								'payables',
								'transactions',
								'settings',
								'complete',
							),
						),
						'format'  => array(
							'description' => esc_html__( 'File format for the export: json, csv, xml.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'json', 'csv', 'xml' ),
							'default'     => 'json',
						),
						'filters' => array(
							'description' => esc_html__( 'Filters to apply to the export data.', 'wc-affiliate' ),
							'type'        => 'object',
							'default'     => array(),
						),
					)
				),
			)
		);

		// Get export status.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/(?P<export_id>[a-zA-Z0-9-]+)/status',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $export_api, 'get_status' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_export_status_args',
					array(
						'export_id' => array(
							'description' => esc_html__( 'ID of the export job to check status for.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Download export file.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/(?P<export_id>[a-zA-Z0-9-]+)/download',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $export_api, 'download' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_export_download_args',
					array(
						'export_id' => array(
							'description' => esc_html__( 'ID of the export job to download.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Delete export.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/(?P<export_id>[a-zA-Z0-9-]+)',
			array(
				'methods'             => WP_REST_Server::DELETABLE,
				'callback'            => array( $export_api, 'delete' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_export_delete_args',
					array(
						'export_id' => array(
							'description' => esc_html__( 'ID of the export job to delete.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Get export jobs list.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/jobs',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $export_api, 'get_jobs' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// Export CSV report directly.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/csv-report',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $export_api, 'export_csv_report' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_export_csv_report_args',
					array(
						'page'   => array(
							'description' => esc_html__( 'Type of data to export: affiliates, payables, visits, referrals, transactions.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
						'status' => array(
							'description' => esc_html__( 'Status filter for the data.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'from'   => array(
							'description' => esc_html__( 'Start date for filtering.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'to'     => array(
							'description' => esc_html__( 'End date for filtering.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);

		// Export table-specific report.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/table-report/(?P<name>[a-zA-Z_]+)',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $export_api, 'export_table_report' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_export_table_report_args',
					array(
						'name' => array(
							'description' => esc_html__( 'Name of the table to export: transactions, shortlinks, visits, referrals.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Export all affiliate data.
		register_rest_route(
			self::API_NAMESPACE,
			'/export/all-data',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $export_api, 'export_all_data' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);

		/**
		 * Action hook fired after affiliate routes registration.
		 */
		do_action( 'wc_affiliate_api_register_affiliate_routes_after' );
	}

	/**
	 * Register user routes
	 */
	protected function register_user_routes() {
		$user_api = new \WC_Affiliate\API\User();

		// Create user endpoint for affiliate creation.
		register_rest_route(
			self::API_NAMESPACE,
			'/users',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $user_api, 'create_user' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_users_create_args',
					array(
						'username'   => array(
							'description' => esc_html__( 'Username for the new user.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
						'email'      => array(
							'description' => esc_html__( 'Email address for the new user.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'email',
							'required'    => true,
						),
						'first_name' => array(
							'description' => esc_html__( 'First name of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'last_name'  => array(
							'description' => esc_html__( 'Last name of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'password'   => array(
							'description' => esc_html__( 'Password for the new user.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Get user profile.
		register_rest_route(
			self::API_NAMESPACE,
			'/users/profile',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $user_api, 'get_user' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);

		// Update user profile.
		register_rest_route(
			self::API_NAMESPACE,
			'/users/profile',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $user_api, 'update_user' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_users_update_profile_args',
					array(
						'first_name'    => array(
							'description' => esc_html__( 'First name of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'last_name'     => array(
							'description' => esc_html__( 'Last name of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'email'         => array(
							'description' => esc_html__( 'Email address of the user.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'email',
						),
						'password'      => array(
							'description' => esc_html__( 'New password for the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'password2'     => array(
							'description' => esc_html__( 'Password confirmation.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'country'       => array(
							'description' => esc_html__( 'Country of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'state'         => array(
							'description' => esc_html__( 'State of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'city'          => array(
							'description' => esc_html__( 'City of the user.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'payout_method' => array(
							'description' => esc_html__( 'Preferred payout method.', 'wc-affiliate' ),
							'type'        => 'string',
							'enum'        => array( 'paypal', 'stripe', 'manual' ),
						),
						'account_info'  => array(
							'description' => esc_html__( 'Manual payment account information.', 'wc-affiliate' ),
							'type'        => 'string',
						),
						'image_url'     => array(
							'description' => esc_html__( 'Avatar image URL.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'uri',
						),
					)
				),
			)
		);

		// Update user avatar.
		register_rest_route(
			self::API_NAMESPACE,
			'/users/avatar',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $user_api, 'update_avatar' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_users_update_avatar_args',
					array(
						'avatar_url' => array(
							'description' => esc_html__( 'URL of the avatar image.', 'wc-affiliate' ),
							'type'        => 'string',
							'format'      => 'uri',
							'required'    => true,
						),
					)
				),
			)
		);

		// Resend verification email.
		register_rest_route(
			self::API_NAMESPACE,
			'/users/resend-verification',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $user_api, 'resend_verification_email' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);

		// Get available users for affiliate creation (non-admin users without affiliate status).
		register_rest_route(
			self::API_NAMESPACE,
			'/users/available',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $user_api, 'get_available_users' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_users_available_args',
					array(
						'page'     => array(
							'description' => esc_html__( 'Current page number for pagination.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 1,
							'minimum'     => 1,
						),
						'per_page' => array(
							'description' => esc_html__( 'Number of users to return per page.', 'wc-affiliate' ),
							'type'        => 'integer',
							'default'     => 20,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'search'   => array(
							'description' => esc_html__( 'Search term to filter users by name or email.', 'wc-affiliate' ),
							'type'        => 'string',
						),
					)
				),
			)
		);
	}

	/**
	 * Register import routes
	 */
	protected function register_import_routes() {
		$import_api = new ImportAPI();

		// Upload import file.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/upload',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $import_api, 'upload_file' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// Get available import types.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/types',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $import_api, 'get_types' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// Validate import file.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/validate',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $import_api, 'validate' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_import_validate_args',
					array(
						'type'     => array(
							'description' => esc_html__( 'Type of data to import: affiliates, visits, referrals, transactions, settings.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array( 'affiliates', 'visits', 'referrals', 'transactions', 'settings' ),
						),
						'file_url' => array(
							'description' => esc_html__( 'URL of the file to validate for import.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'format'      => 'uri',
						),
					)
				),
			)
		);

		// Start import.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/start',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $import_api, 'start' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_import_start_args',
					array(
						'type'     => array(
							'description' => esc_html__( 'Type of data to import: affiliates, visits, referrals, transactions, settings.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'enum'        => array( 'affiliates', 'visits', 'referrals', 'transactions', 'settings' ),
						),
						'file_url' => array(
							'description' => esc_html__( 'URL of the file to import from.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
							'format'      => 'uri',
						),
						'options'  => array(
							'description' => esc_html__( 'Import options and settings.', 'wc-affiliate' ),
							'type'        => 'object',
						),
					)
				),
			)
		);

		// Get import status.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/(?P<import_id>[a-zA-Z0-9-]+)/status',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $import_api, 'get_status' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_import_status_args',
					array(
						'import_id' => array(
							'description' => esc_html__( 'ID of the import job to check status for.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Cancel import.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/(?P<import_id>[a-zA-Z0-9-]+)/cancel',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $import_api, 'cancel' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_import_cancel_args',
					array(
						'import_id' => array(
							'description' => esc_html__( 'ID of the import job to cancel.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Delete import.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/(?P<import_id>[a-zA-Z0-9-]+)',
			array(
				'methods'             => WP_REST_Server::DELETABLE,
				'callback'            => array( $import_api, 'delete' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_import_delete_args',
					array(
						'import_id' => array(
							'description' => esc_html__( 'ID of the import job to delete.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		// Get import jobs list.
		register_rest_route(
			self::API_NAMESPACE,
			'/import/jobs',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $import_api, 'get_jobs' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);
	}

	/**
	 * Register settings API routes
	 */
	protected function register_settings_routes() {
		$settings_api = new SettingsAPI();

		// Settings pages.
		$pages    = wca_get_settings_pages();
		$page_ids = array_keys( $pages );

		$page_ids[] = '';

		// Get settings configuration.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/config',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $settings_api, 'get_config' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_settings_config_args',
					array(
						'page' => array(
							'description' => __( 'Settings page identifier. Leave empty to update all pages.', 'wc-affiliate' ),
							'enum'        => $page_ids,
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Get settings values.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/values',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $settings_api, 'get_values' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_settings_values_args',
					array(
						'page' => array(
							'description' => __( 'Settings page identifier. Leave empty to update all pages.', 'wc-affiliate' ),
							'enum'        => $page_ids,
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Get settings defaults.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/defaults',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $settings_api, 'get_defaults' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_settings_defaults_args',
					array(
						'page' => array(
							'description' => __( 'Settings page identifier. Leave empty to get all pages defaults.', 'wc-affiliate' ),
							'enum'        => $page_ids,
							'type'        => 'string',
							'required'    => false,
						),
					)
				),
			)
		);

		// Update settings.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/update',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $settings_api, 'update' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_settings_update_args',
					array(
						'page'   => array(
							'description' => __( 'Settings page identifier. Leave empty to update all pages.', 'wc-affiliate' ),
							'enum'        => $page_ids,
							'type'        => 'string',
							'required'    => false,
							'default'     => '',
						),
						'values' => array(
							'required'          => true,
							'description'       => __( 'Settings values. When page is empty, this should contain all pages data in hierarchical format: { page_id: { section_id: { field_id: value } } }. When page is specified, this should contain the page data in hierarchical format.', 'wc-affiliate' ),
							'validate_callback' => function ( $param ) {
								return is_array( $param );
							},
						),
					)
				),
			)
		);

		// Reset settings to defaults.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/reset',
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $settings_api, 'reset' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => apply_filters(
					'wc_affiliate_rest_api_settings_reset_args',
					array(
						'page' => array(
							'description' => __( 'Settings page identifier. Leave empty to update all pages.', 'wc-affiliate' ),
							'enum'        => $page_ids,
							'type'        => 'string',
							'required'    => false,
							'default'     => '',
						),
					)
				),
			)
		);

		// Get payment methods.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/payment-methods',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $settings_api, 'get_payment_methods' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);

		// Get countries list.
		register_rest_route(
			self::API_NAMESPACE,
			'/settings/countries',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $settings_api, 'get_countries' ),
				'permission_callback' => array( $this, 'check_affiliate_permissions' ),
			)
		);
	}

	/**
	 * Register notices routes
	 */
	protected function register_notices_routes() {
		$notices_api = new NoticesAPI();

		// Dismiss notice.
		register_rest_route(
			self::API_NAMESPACE,
			'/notices/dismiss',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $notices_api, 'dismiss_notice' ),
				'permission_callback' => '__return_true',
				'args'                => apply_filters(
					'wc_affiliate_rest_api_notices_dismiss_args',
					array(
						'notice_type' => array(
							'description' => esc_html__( 'Type of notice to dismiss.', 'wc-affiliate' ),
							'type'        => 'string',
							'required'    => true,
						),
					)
				),
			)
		);

		register_rest_route(
			self::API_NAMESPACE,
			'/notices/resolve-dependency',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $notices_api, 'resolve_required_dependency' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);
	}

	/**
	 * Check permissions for affiliate operations
	 *
	 * @param WP_REST_Request $request The request object.
	 *
	 * @return bool|WP_Error True if permissions are valid, WP_Error if not
	 */
	public function check_affiliate_permissions( WP_REST_Request $request ) {
		if ( ! is_user_logged_in() ) {
			return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.', 'wc-affiliate' ), array( 'status' => 401 ) );
		}

		// Admins can access all affiliate data.
		if ( current_user_can( 'manage_options' ) ) {
			return true;
		}

		$current_user_id = get_current_user_id();

		// Get the affiliate ID being requested (check both 'affiliate_id' and 'id' parameters).
		$affiliate_id = ! empty( $request->get_param( 'affiliate_id' ) ) ? (int) $request->get_param( 'affiliate_id' ) : $current_user_id;

		// Check if the current user is an affiliate.
		$current_user_affiliate = new Affiliate( $affiliate_id );
		if ( ! $current_user_affiliate->exists() || ! $current_user_affiliate->is_active() ) {
			return new WP_Error( 'rest_forbidden', __( 'You do not have permission to access affiliate data.', 'wc-affiliate' ), array( 'status' => 403 ) );
		}

		// Affiliates can only access their own data.
		if ( $current_user_id !== $affiliate_id ) {
			return new WP_Error( 'rest_forbidden', __( 'You can only access your own affiliate data.', 'wc-affiliate' ), array( 'status' => 403 ) );
		}

		return true;
	}

	/**
	 * Check permissions for admin operations
	 *
	 * @return bool|WP_Error True if user has permissions, WP_Error object otherwise.
	 */
	public function check_admin_permissions() {
		if ( ! is_user_logged_in() ) {
			return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.', 'wc-affiliate' ), array( 'status' => 401 ) );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			return new WP_Error( 'rest_forbidden', __( 'You do not have permission to access this resource.', 'wc-affiliate' ), array( 'status' => 403 ) );
		}

		return true;
	}

	/**
	 * Check permissions for affiliate operations
	 *
	 * @return bool|WP_Error True if user has permissions, WP_Error object otherwise.
	 */
	public function check_logged_in_permissions() {
		if ( ! is_user_logged_in() ) {
			return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.', 'wc-affiliate' ), array( 'status' => 401 ) );
		}

		return true;
	}
}
