<?php

namespace WeeConnectPay\WordPress\Plugin\includes;

use WeeConnectPay\AccessToken;
use WeeConnectPay\CloverApp;
use WeeConnectPay\CloverMerchant;
use WeeConnectPay\CloverEmployee;
use WeeConnectPay\Environment;
use WeeConnectPay\Exceptions\SettingsInitializationException;
use WeeConnectPay\Exceptions\WeeConnectPayException;
use WeeConnectPay\Integrations\IntegrationSettings;
use WeeConnectPay\Integrations\DeviceFlowManager;
use WeeConnectPay\Integrations\OAuthTokenManager;
use WeeConnectPay\Settings;
use WeeConnectPay\StandardizedResponse;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Response;
use WeeConnectPay\Integrations\Logger;
use WeeConnectPay\Integrations\LogService;

class WeeConnectPayController extends WP_REST_Controller {

	protected $namespace = 'weeconnectpay/v1';
	private $wp_env;
	private $url_api;

	public function __construct() {
		$this->wp_env  = WeeConnectPayUtilities::get_wp_env();
		$this->url_api = Environment::getApiBaseUrl();
	}

	public function register_routes() {
		// Plugin Registration request from our API
		$this->registerIntegrationRegistrationRoute();

		// Plugin dependency check
		$this->registerPluginDependencyCheckRoute();
		$this->getPluginSettings();
		$this->registerAllSettingsRoutes();
		$this->registerDisconnectRoute();
		$this->registerConnectRoute();
		$this->registerDeviceFlowRoutes();
		$this->registerEnvironmentSwitchRoute();
	}

	/**
	 * Not currently used
	 */
	public function registerPluginDependencyCheckRoute() {
		$namespace = 'weeconnectpay/v1';
		$path      = 'integration/dependencies';

		register_rest_route(
			$namespace,
			'/' . $path,
			array(
				array(
					'methods'             => 'GET',
					'callback'            => array( $this, 'get_integration_dependencies' ),
					'permission_callback' => array( $this, 'get_integration_dependencies_permissions_check' ),
				),
			)
		);
	}

	/**
	 * Registers the plugin settings route
	 *
	 * @return void
	 */
	public function getPluginSettings() {
		$namespace = 'weeconnectpay/v1';
		$path      = 'plugin/settings';

		register_rest_route(
			$namespace,
			'/' . $path,
			array(
				array(
					'methods'             => 'GET',
					'callback'            => array( $this, 'get_plugin_settings' ),
					'permission_callback' => array( $this, 'get_plugin_settings_permissions_check' ),
				),
			)
		);
	}

	public function get_plugin_settings_permissions_check( $request ): bool {
		return true;
	}

	/**
	 * @return object StandardizedResponse::emitError | StandardizedResponse::emitSuccess
	 */
	public function get_plugin_settings() {
		try {
			$integrationSettings = new IntegrationSettings();
			// TODO: Make a settings response object

			// Should either return the login page settings OR the full settings we need to display.
			$merchant = CloverMerchant::getFromIntegrationSettings( $integrationSettings);
			$app = CloverApp::getFromIntegrationSettings( $integrationSettings);
			return StandardizedResponse::emitSuccess( json_decode(json_encode( ['app' => $app, 'merchant' => $merchant])));
		} catch ( WeeConnectPayException $e ) {
			return StandardizedResponse::emitError( $e->toObject() );
		}
	}


	public function get_integration_dependencies_permissions_check( $request ): bool {
		return true;
	}

	/**
	 * @deprecated
	 * @return object StandardizedResponse::emitError | StandardizedResponse::emitSuccess
	 */
	public function get_integration_dependencies(): object {
		try {
			$integration_settings = new IntegrationSettings();
			//$integration_settings->retrieve();
			return $integration_settings->validateDependencies();
		} catch ( WeeConnectPayException $e ) {
			return StandardizedResponse::emitError( $e->toObject() );
		}
	}

	public function set_plugin_configs_permissions_check( $request ): bool {
		return true;
	}

	/**
	 * @param $request
	 *
	 * @updated 3.7.0
	 * @return object|WP_Error
	 */
	public function set_plugin_configs( $request ) {

		$body = json_decode( $request->get_body() );

		// get values needed
		if ( ! isset( $body->integration_id, $body->auth_hash ) ) {
			return new WP_Error( 'invalid_request', 'the request is missing required parameters', array( 'status' => 400 ) );
		}

		$response = wp_remote_post(
			$this->url_api . "/v1/integration/$body->integration_id/token",
			array(
				'headers' => array(
					'Accept'       => 'application/json',
					'Content-Type' => 'application/json',
				),
				'body'    => wp_json_encode( array( 'auth_hash' => $body->auth_hash ) ),
				'timeout' => 60,
			)
		);

		$payload = json_decode( wp_remote_retrieve_body( $response ) ); // stringified json sent from our API, decode it.


		// Check payload
		$validationResult = $this->validate_set_plugin_config_payload( $payload );
		if ( $validationResult !== true ) {
			if ( $validationResult instanceof WP_Error ) {
				return $validationResult;
			} else {
				LogService::error('An unexpected error has occurred while validating the set_plugin_config payload.');
				return new WP_Error('internal_error', 'An unexpected error has occurred while validating the set_plugin_config payload.', array('status' => 500 ) );
			}
		}


		$integration_settings = new IntegrationSettings();
		try {
			$integration_settings->saveAfterAuth( $payload );

			return StandardizedResponse::emitSuccess( (object) ['message' => 'Settings were properly saved after authenticating.']);
		} catch ( SettingsInitializationException $exception ) {

			return StandardizedResponse::emit( $exception->toObject() );
		} catch ( \Throwable $exception ) {

			return StandardizedResponse::emit( $exception );
		}

		//		return new WP_REST_Response( $is_success, $is_success? 200 : 500 );
	}


	/**
	 * @param $payload
	 *
	 * @return true|WP_Error
	 * @since 3.7.0
	 */
	function validate_set_plugin_config_payload($payload) {
		$required_fields = [
			'uuid' => false,
			'token' => false,
			'clover_merchant' => ['name', 'uuid'],
			'clover_app' => ['name', 'uuid'],
			'clover_employee' => ['name', 'uuid'],
			'integrable_backend' => ['db_prefix']
		];

		if ( empty($payload->integration) ){
			$error_message = 'Missing field: integration field is missing entirely';
			LogService::error("WeeConnectPay Plugin Authentication Error: $error_message");
			return new WP_Error('invalid_response', $error_message, array('status' => 400));
		} else {
			$integration = $payload->integration;
		}

		foreach ($required_fields as $field => $subfields) {
			if (!isset($integration->$field)) {
				$error_message = sprintf('Missing field: integration.%s', $field);
				LogService::error("WeeConnectPay Plugin Authentication Error: $error_message");
				return new WP_Error('invalid_response', $error_message, array('status' => 400));
			}

			$value = $integration->$field;
			if (is_array($subfields)) {
				foreach ($subfields as $subfield) {
					if (!isset($value->$subfield)) {
						$error_message = sprintf('Missing field: integration.%s.%s', $field, $subfield);
						LogService::error("WeeConnectPay Plugin Authentication Error: $error_message");
						return new WP_Error('invalid_response', $error_message, array('status' => 400));
					}
					if (empty($value->$subfield)) {
						$error_message = sprintf('Empty field: integration.%s.%s', $field, $subfield);
						LogService::error("WeeConnectPay Plugin Authentication Error: $error_message");
						return new WP_Error('invalid_response', $error_message, array('status' => 400));
					}
				}
			} else {
				if (empty($value)) {
					$error_message = sprintf('Empty field: integration.%s', $field);
					LogService::error("WeeConnectPay Plugin Authentication Error: $error_message");
					return new WP_Error('invalid_response', $error_message, array('status' => 400));
				}
			}
		}
		return true;
	}



	/**
	 * Registers GET and POST routes for retrieving and updating all plugin settings.
	 *
	 * @since 3.18.0
	 * @return void
	 */
	public function registerAllSettingsRoutes() {
		$namespace = 'weeconnectpay/v1';
		$path      = 'plugin/settings/all';

		register_rest_route(
			$namespace,
			'/' . $path,
			array(
				array(
					'methods'             => 'GET',
					'callback'            => array( $this, 'get_all_plugin_settings' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'update_all_plugin_settings' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
			)
		);
	}

	/**
	 * Registers POST route for disconnecting from Clover.
	 *
	 * @since 3.18.0
	 * @return void
	 */
	public function registerDisconnectRoute() {
		$namespace = 'weeconnectpay/v1';
		$path      = 'plugin/disconnect';

		register_rest_route(
			$namespace,
			'/' . $path,
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'disconnect_plugin' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
			)
		);
	}

	/**
	 * Registers POST route for switching environment.
	 *
	 * @since 4.1.0
	 * @return void
	 */
	public function registerEnvironmentSwitchRoute() {
		register_rest_route(
			'weeconnectpay/v1',
			'/plugin/environment',
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'switch_environment' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
			)
		);
	}

	/**
	 * POST /plugin/environment — Switch the active environment.
	 *
	 * @since 4.1.0
	 * @param $request
	 * @return WP_REST_Response
	 */
	public function switch_environment( $request ) {
		$body = json_decode( $request->get_body(), true );
		$env  = isset( $body['environment'] ) ? $body['environment'] : null;

		if ( ! $env || ! in_array( $env, Environment::all(), true ) ) {
			return new WP_REST_Response( array( 'error' => 'Invalid environment.' ), 400 );
		}

		Environment::setCurrentKey( $env );

		LogService::info( 'Environment switched to: ' . $env );

		return new WP_REST_Response( array(
			'success'     => true,
			'environment' => $env,
		), 200 );
	}

	/**
	 * Permission check requiring manage_woocommerce capability.
	 *
	 * @since 3.18.0
	 * @return bool
	 */
	public function manage_woocommerce_permissions_check(): bool {
		return current_user_can( 'manage_woocommerce' );
	}

	/**
	 * GET /plugin/settings/all — Returns all current settings from IntegrationSettings + merchant/app info.
	 *
	 * @since 3.18.0
	 * @return WP_REST_Response
	 */
	public function get_all_plugin_settings() {
		try {
			$integrationSettings = new IntegrationSettings();

			$settings = array(
				'transaction_mode'                           => $integrationSettings->getTransactionModeOrDefault() ?: 'order_payment',
				'three_d_secure_beta'                        => $integrationSettings->getThreeDSecureBetaOrDefault() ?: '0',
				'wizard_completed'                           => $integrationSettings->getWizardCompletedOrDefault() ?: '0',
				'auth_method'                                => $integrationSettings->getAuthMethodOrDefault(),
				'post_tokenization_verification'             => $integrationSettings->getPostTokenizationVerificationOrDefault() ?: '0',
				'google_recaptcha'                           => $integrationSettings->getGoogleRecaptchaOrDefault() ?: '0',
				'google_recaptcha_site_key'                  => $integrationSettings->getGoogleRecaptchaSiteKeyOrDefault(),
				'google_recaptcha_secret_key'                => $integrationSettings->getGoogleRecaptchaSecretKeyOrDefault(),
				'google_recaptcha_minimum_human_score_threshold' => $integrationSettings->getGoogleRecaptchaMinimumHumanScoreThresholdOrDefault() ?: '0.5',
				'honeypot_field'                             => $integrationSettings->getHoneypotFieldOrDefault() ?: '0',
				'google_pay'                                 => $integrationSettings->getGooglePayOrDefault() ?: '0',
				'debug_mode'                                 => $integrationSettings->getDebugModeOrDefault() ? '1' : '0',
				'clover_order_printing'                      => $integrationSettings->getCloverOrderPrintingOrDefault() ? '1' : '0',
				'clover_order_printing_recurring'             => $integrationSettings->getCloverOrderPrintingRecurringOrDefault() ? '1' : '0',
			);

			// Add merchant info if available
			$merchantInfo = array();
			try {
				$merchant = $integrationSettings->getCloverMerchant();
				$merchantInfo['merchant_name'] = $merchant->getName();
				$merchantInfo['merchant_id']   = $merchant->getUuid();
			} catch ( \Throwable $e ) {
				// Merchant info not available
			}

			// Add app info if available
			$appInfo = array();
			try {
				$app = $integrationSettings->getCloverApp();
				$appInfo['app_name'] = $app->getName();
				$appInfo['app_id']   = $app->getUuid();
			} catch ( \Throwable $e ) {
				// App info not available
			}

			// Environment info
			$environmentsWithStatus = array();
			foreach ( Environment::getVisibleEnvironments() as $envOption ) {
				$envOption['isConnected'] = Environment::isConnected( $envOption['key'] );
				$environmentsWithStatus[] = $envOption;
			}

			return new WP_REST_Response( array(
				'settings'     => $settings,
				'merchant'     => $merchantInfo,
				'app'          => $appInfo,
				'environment'  => Environment::getCurrentKey(),
				'environments' => $environmentsWithStatus,
			), 200 );
		} catch ( \Throwable $e ) {
			LogService::error( 'Error fetching all plugin settings: ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => $e->getMessage() ), 500 );
		}
	}

	/**
	 * POST /plugin/settings/all — Accepts partial settings object, updates IntegrationSettings AND syncs to WC gateway options.
	 *
	 * @since 3.18.0
	 * @param $request
	 * @return WP_REST_Response
	 */
	public function update_all_plugin_settings( $request ) {
		try {
			$body = json_decode( $request->get_body(), true );
			if ( ! is_array( $body ) ) {
				return new WP_REST_Response( array( 'error' => 'Invalid request body' ), 400 );
			}

			$integrationSettings = new IntegrationSettings();

			// Map of setting key => [setter method, WC gateway option key, is boolean toggle]
			$settingMap = array(
				'transaction_mode'              => array( 'setTransactionMode', 'transaction_mode', false ),
				'three_d_secure_beta'           => array( 'setThreeDSecureBeta', 'three_d_secure_beta', true ),
				'wizard_completed'              => array( 'setWizardCompleted', null, false ),
				'post_tokenization_verification' => array( 'setPostTokenizationVerification', 'post_tokenization_verification', true ),
				'google_recaptcha'              => array( 'setGoogleRecaptcha', 'google_recaptcha_enabled', true ),
				'google_recaptcha_site_key'     => array( 'setGoogleRecaptchaSiteKey', 'google_recaptcha_site_key', false ),
				'google_recaptcha_secret_key'   => array( 'setGoogleRecaptchaSecretKey', 'google_recaptcha_secret_key', false ),
				'google_recaptcha_minimum_human_score_threshold' => array( 'setGoogleRecaptchaMinimumHumanScoreThreshold', 'min_human_score_threshold', false ),
				'honeypot_field'                => array( 'setHoneypotField', 'honeypot_field_enabled', true ),
				'google_pay'                    => array( 'setGooglePay', 'google_pay_enabled', true ),
				'debug_mode'                    => array( 'setDebugMode', 'debug_mode', true ),
				'clover_order_printing'         => array( 'setCloverOrderPrinting', 'clover_order_printing', true ),
				'clover_order_printing_recurring' => array( 'setCloverOrderPrintingRecurring', 'clover_order_printing_recurring', true ),
			);

			// Get current WC gateway options for syncing
			$wcOptions = get_option( IntegrationSettings::DB_KEY_WOOCOMMERCE_INTEGRATION, array() );
			if ( ! is_array( $wcOptions ) ) {
				$wcOptions = array();
			}
			$wcOptionsUpdated = false;

			foreach ( $body as $key => $value ) {
				if ( ! isset( $settingMap[ $key ] ) ) {
					continue;
				}

				$setterMethod = $settingMap[ $key ][0];
				$wcKey        = $settingMap[ $key ][1];
				$isBoolToggle = $settingMap[ $key ][2];

				// Sanitize input
				$sanitizedValue = sanitize_text_field( $value );

				// Update IntegrationSettings (source of truth)
				$integrationSettings->$setterMethod( $sanitizedValue );

				// Sync to WC gateway options if applicable
				if ( $wcKey !== null ) {
					// WC gateway uses 'yes'/'no' for checkboxes, plain values for text fields
					if ( $isBoolToggle ) {
						$wcOptions[ $wcKey ] = ( $sanitizedValue === '1' || $sanitizedValue === 'yes' ) ? 'yes' : 'no';
					} else {
						$wcOptions[ $wcKey ] = $sanitizedValue;
					}
					$wcOptionsUpdated = true;
				}
			}

			// Save WC gateway options if any were updated
			if ( $wcOptionsUpdated ) {
				update_option( IntegrationSettings::DB_KEY_WOOCOMMERCE_INTEGRATION, $wcOptions );
			}

			// Return fresh settings
			return $this->get_all_plugin_settings();
		} catch ( \Throwable $e ) {
			LogService::error( 'Error updating all plugin settings: ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => $e->getMessage() ), 500 );
		}
	}

	/**
	 * POST /plugin/disconnect — Disconnects from Clover.
	 *
	 * @since 3.18.0
	 * @param $request
	 * @return WP_REST_Response
	 */
	public function disconnect_plugin( $request ) {
		try {
			$body = json_decode( $request->get_body(), true );
			$rememberSettings = isset( $body['rememberSettings'] ) ? (bool) $body['rememberSettings'] : true;

			IntegrationSettings::forceLogout( $rememberSettings );

			return new WP_REST_Response( array(
				'success' => true,
				'message' => $rememberSettings
					? 'Disconnected from Clover. Your settings have been preserved.'
					: 'Disconnected from Clover. All settings have been removed.',
			), 200 );
		} catch ( \Throwable $e ) {
			LogService::error( 'Error during plugin disconnect: ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => $e->getMessage() ), 500 );
		}
	}

	/**
	 * Registers POST route for connecting via OAuth2 Client Credentials.
	 *
	 * @since 3.19.0
	 * @return void
	 */
	public function registerConnectRoute() {
		$namespace = 'weeconnectpay/v1';
		$path      = 'plugin/connect';

		register_rest_route(
			$namespace,
			'/' . $path,
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'connect_plugin' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
			)
		);
	}

	/**
	 * POST /plugin/connect — Exchanges OAuth2 client credentials for a JWT and saves all settings.
	 *
	 * @since 3.19.0
	 * @param $request
	 * @return WP_REST_Response
	 */
	public function connect_plugin( $request ) {
		try {
			$body = json_decode( $request->get_body(), true );
			if ( ! is_array( $body ) || empty( $body['client_id'] ) || empty( $body['client_secret'] ) ) {
				return new WP_REST_Response( array( 'error' => 'Client ID and Client Secret are required.' ), 400 );
			}

			$clientId     = sanitize_text_field( $body['client_id'] );
			$clientSecret = sanitize_text_field( $body['client_secret'] );

			$result = $this->finalizeConnection( $clientId, $clientSecret );

			return new WP_REST_Response( $result, 200 );
		} catch ( WeeConnectPayException $e ) {
			LogService::error( 'Plugin connect failed: ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => $e->getMessage() ), 400 );
		} catch ( \Throwable $e ) {
			LogService::error( 'Plugin connect failed (unexpected): ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => 'An unexpected error occurred.' ), 500 );
		}
	}

	/**
	 * Exchanges client credentials for an access token, fetches caller identity,
	 * and saves all integration settings. Shared by connect_plugin and device flow.
	 *
	 * @since 3.20.0
	 * @param string $clientId
	 * @param string $clientSecret
	 * @return array Response data with success, message, and merchant info
	 * @throws WeeConnectPayException
	 */
	private function finalizeConnection( string $clientId, string $clientSecret ): array {
		$tokenManager = new OAuthTokenManager();

		// Step 1: Exchange credentials for access token
		$tokenResponse = $tokenManager->exchangeCredentials( $clientId, $clientSecret );

		$accessToken = $tokenResponse->access_token;
		$expiresAt   = isset( $tokenResponse->expires_in )
			? date( 'Y-m-d H:i:s', time() + $tokenResponse->expires_in )
			: null;

		// Step 2: Fetch caller identity to get merchant/employee/app/pakms info
		$identity = $tokenManager->fetchCallerIdentity( $accessToken );

		// Step 3: Save everything to IntegrationSettings
		$integrationSettings = new IntegrationSettings();

		// Save OAuth credentials
		$integrationSettings->setOauthClientId( $clientId );
		$integrationSettings->setOauthClientSecret( $clientSecret );
		$integrationSettings->setAuthMethod( 'client_credentials' );

		// Save access token
		$integrationSettings->setAccessToken(
			new AccessToken(
				$accessToken,
				isset( $tokenResponse->scopes ) ? (array) $tokenResponse->scopes : array(),
				'client_credentials',
				$expiresAt
			)
		);

		// Save identity info (merchant, employee, app, pakms)
		// The get-caller-identity endpoint returns a flat structure with top-level keys,
		// while the legacy auth endpoint nests everything under `integration`.
		if ( isset( $identity->integration->uuid ) ) {
			$integrationSettings->setIntegrationUuid( $identity->integration->uuid );
		}
		if ( isset( $identity->integration->integrable_type ) ) {
			$integrationSettings->setPlatformType( $identity->integration->integrable_type );
		}

		// Merchant: flat (get-caller-identity) or nested (legacy)
		if ( isset( $identity->merchant ) ) {
			$integrationSettings->setCloverMerchant(
				new CloverMerchant( $identity->merchant->name, $identity->merchant->uuid )
			);
		} elseif ( isset( $identity->integration->clover_merchant ) ) {
			$integrationSettings->setCloverMerchant(
				new CloverMerchant(
					$identity->integration->clover_merchant->name,
					$identity->integration->clover_merchant->uuid
				)
			);
		}

		// Employee: flat or nested
		if ( isset( $identity->employee ) ) {
			$integrationSettings->setCloverEmployee(
				new CloverEmployee( $identity->employee->name, $identity->employee->uuid )
			);
		} elseif ( isset( $identity->integration->clover_employee ) ) {
			$integrationSettings->setCloverEmployee(
				new CloverEmployee(
					$identity->integration->clover_employee->name,
					$identity->integration->clover_employee->uuid
				)
			);
		}

		// App: flat or nested
		if ( isset( $identity->app ) ) {
			$integrationSettings->setCloverApp(
				new CloverApp( $identity->app->name, $identity->app->uuid )
			);
		} elseif ( isset( $identity->integration->clover_app ) ) {
			$integrationSettings->setCloverApp(
				new CloverApp(
					$identity->integration->clover_app->name,
					$identity->integration->clover_app->uuid
				)
			);
		}

		// Public access key: flat (get-caller-identity) or nested (legacy)
		if ( isset( $identity->public_access_key->key ) ) {
			$integrationSettings->setPublicAccessKey( $identity->public_access_key->key );
		} elseif ( isset( $identity->integration->clover_access_token->public_key->key ) ) {
			$integrationSettings->setPublicAccessKey( $identity->integration->clover_access_token->public_key->key );
		} else {
			LogService::warning( 'Public access key (pakms) not found in caller identity response.' );
		}

		// Save site context info
		global $wpdb;
		$integrationSettings->setIntegrationWpdbPrefix( sanitize_text_field( $wpdb->prefix ) );
		$integrationSettings->setIntegrationSiteUrl( sanitize_url( site_url() ) );

		// Build response
		$responseData = array(
			'success' => true,
			'message' => 'Connected successfully.',
		);
		if ( isset( $identity->merchant ) ) {
			$responseData['merchant'] = array(
				'name' => $identity->merchant->name,
				'id'   => $identity->merchant->uuid,
			);
		} elseif ( isset( $identity->integration->clover_merchant ) ) {
			$responseData['merchant'] = array(
				'name' => $identity->integration->clover_merchant->name,
				'id'   => $identity->integration->clover_merchant->uuid,
			);
		}

		LogService::info( 'Plugin connected via client credentials authentication.' );

		return $responseData;
	}

	/**
	 * Registers device flow REST endpoints.
	 *
	 * @since 3.20.0
	 * @return void
	 */
	public function registerDeviceFlowRoutes() {
		$namespace = 'weeconnectpay/v1';

		register_rest_route(
			$namespace,
			'/connect/authorize',
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'device_authorize' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$namespace,
			'/connect/poll',
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'device_poll' ),
					'permission_callback' => array( $this, 'manage_woocommerce_permissions_check' ),
				),
			)
		);
	}

	/**
	 * POST /connect/authorize — Requests a device code and stores it server-side.
	 *
	 * Returns user_code and verification URL to the frontend. The device_code
	 * stays server-side in a WordPress transient (never sent to the browser).
	 *
	 * @since 3.20.0
	 * @return WP_REST_Response
	 */
	public function device_authorize() {
		try {
			$deviceFlowManager = new DeviceFlowManager();
			$response          = $deviceFlowManager->requestDeviceCode();

			// Store device_code server-side (keyed per user, 15-min expiry)
			$transientKey = 'weeconnectpay_device_code_' . get_current_user_id() . '_' . Environment::getCurrentKey();
			set_transient( $transientKey, $response->device_code, 900 );

			return new WP_REST_Response( array(
				'user_code'                  => $response->user_code,
				'verification_uri_complete'  => isset( $response->verification_uri_complete ) ? $response->verification_uri_complete : null,
				'verification_uri'           => isset( $response->verification_uri ) ? $response->verification_uri : null,
				'expires_in'                 => isset( $response->expires_in ) ? (int) $response->expires_in : 900,
				'interval'                   => isset( $response->interval ) ? (int) $response->interval : 5,
			), 200 );
		} catch ( WeeConnectPayException $e ) {
			LogService::error( 'Device authorize failed: ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => $e->getMessage() ), 400 );
		} catch ( \Throwable $e ) {
			LogService::error( 'Device authorize failed (unexpected): ' . $e->getMessage() );
			return new WP_REST_Response( array( 'error' => 'An unexpected error occurred.' ), 500 );
		}
	}

	/**
	 * POST /connect/poll — Polls for device flow credentials using stored device_code.
	 *
	 * On success, executes the full connection flow (token exchange + identity fetch + settings save).
	 *
	 * @since 3.20.0
	 * @return WP_REST_Response
	 */
	public function device_poll() {
		try {
			$transientKey = 'weeconnectpay_device_code_' . get_current_user_id() . '_' . Environment::getCurrentKey();
			$deviceCode   = get_transient( $transientKey );

			if ( ! $deviceCode ) {
				return new WP_REST_Response( array(
					'status'  => 'expired',
					'message' => 'Device flow session has expired or was not started.',
				), 200 );
			}

			$deviceFlowManager = new DeviceFlowManager();
			$response          = $deviceFlowManager->pollForCredentials( $deviceCode );

			// Success: API returned client_id + client_secret
			if ( $response->http_code === 200 && isset( $response->client_id, $response->client_secret ) ) {
				// Clean up transient
				delete_transient( $transientKey );

				// Execute the full connection flow
				$result = $this->finalizeConnection( $response->client_id, $response->client_secret );

				return new WP_REST_Response( array(
					'status'   => 'connected',
					'message'  => $result['message'],
					'merchant' => isset( $result['merchant'] ) ? $result['merchant'] : null,
				), 200 );
			}

			// Handle error responses from the API
			$error = isset( $response->error ) ? $response->error : 'unknown';

			switch ( $error ) {
				case 'authorization_pending':
					return new WP_REST_Response( array( 'status' => 'pending' ), 200 );

				case 'slow_down':
					return new WP_REST_Response( array(
						'status'   => 'slow_down',
						'interval' => isset( $response->interval ) ? (int) $response->interval : 10,
					), 200 );

				case 'expired_token':
					delete_transient( $transientKey );
					return new WP_REST_Response( array( 'status' => 'expired' ), 200 );

				case 'access_denied':
					delete_transient( $transientKey );
					return new WP_REST_Response( array( 'status' => 'denied' ), 200 );

				case 'invalid_grant':
					delete_transient( $transientKey );
					return new WP_REST_Response( array( 'status' => 'invalid' ), 200 );

				default:
					$message = isset( $response->message ) ? $response->message : 'Unknown error';
					return new WP_REST_Response( array(
						'status'  => 'error',
						'message' => $message,
					), 200 );
			}
		} catch ( WeeConnectPayException $e ) {
			LogService::error( 'Device poll failed: ' . $e->getMessage() );
			return new WP_REST_Response( array(
				'status'  => 'error',
				'message' => $e->getMessage(),
			), 200 );
		} catch ( \Throwable $e ) {
			LogService::error( 'Device poll failed (unexpected): ' . $e->getMessage() );
			return new WP_REST_Response( array(
				'status'  => 'error',
				'message' => 'An unexpected error occurred.',
			), 500 );
		}
	}

	private function registerIntegrationRegistrationRoute(): void {
		$namespace = 'weeconnectpay/v1';
		$path      = 'plugin/register';

		register_rest_route(
			$namespace,
			'/' . $path,
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'set_plugin_configs' ),
					'permission_callback' => array( $this, 'set_plugin_configs_permissions_check' ),
				),

			)
		);
	}

}
