<?php
/**
 * Native Integrations class for SureForms Pro (Refactored)
 * Handles the native integrations system including script enqueuing and API endpoints.
 *
 * @package sureforms-pro.
 * @since 1.13.0
 */

namespace SRFM_Pro\Inc\Pro;

use SRFM\Inc\Helper;
use SRFM_Pro\Inc\Helper as Pro_Helper;
use SRFM_Pro\Inc\Pro\Native_Integrations\OAuth_Handler;
use SRFM_Pro\Inc\Pro\Native_Integrations\Services\Config_Manager;
use SRFM_Pro\Inc\Pro\Native_Integrations\Services\Connection_Tester;
use SRFM_Pro\Inc\Pro\Native_Integrations\Services\Field_Manager;
use SRFM_Pro\Inc\Pro\Native_Integrations\Services\Workflow_Processor;
use SRFM_Pro\Inc\Pro\Native_Integrations\Utils\Integration_Utils;
use SRFM_Pro\Inc\Traits\Get_Instance;

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

/**
 * Native Integrations class for SureForms Pro
 * Manages the native integrations system.
 *
 * @since 1.13.0
 */
class Native_Integrations {
	use Get_Instance;

	/**
	 * Service instances
	 *
	 * @var array
	 */
	private $services = [];

	/**
	 * Constructor
	 *
	 * @since 1.13.0
	 * @return void
	 */
	public function __construct() {
		$this->init_services();
		$this->register_plugin_handlers();

		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
		add_filter( 'srfm_rest_api_endpoints', [ $this, 'register_endpoints' ] );
		add_action( 'srfm_register_additional_post_meta', [ $this, 'add_native_integrations_meta' ] );
	}

	/**
	 * Enqueue native integrations assets.
	 *
	 * @since 1.13.0
	 * @return void
	 */
	public function enqueue_assets() {
		$current_screen = get_current_screen();

		if ( is_null( $current_screen ) ) {
			return;
		}

		// Enqueue on SureForms global settings page.
		$is_screen_sureforms_form_settings = Helper::validate_request_context( 'sureforms_form_settings', 'page' );

		// Enqueue on individual form edit pages.
		$is_post_type_sureforms_form = $current_screen && defined( 'SRFM_FORMS_POST_TYPE' ) && SRFM_FORMS_POST_TYPE === $current_screen->post_type;

		if ( ! $is_screen_sureforms_form_settings && ! $is_post_type_sureforms_form ) {
			return;
		}

		$this->enqueue_scripts();
	}

	/**
	 * Register REST API endpoints
	 *
	 * @param array $endpoints Existing endpoints.
	 * @return array Updated endpoints.
	 * @since 1.13.0
	 */
	public function register_endpoints( $endpoints ) {
		return array_merge(
			$endpoints,
			[
				'native-integrations/config'          => [
					'methods'             => 'GET,POST',
					'callback'            => [ $this->services['config_manager'], 'handle_integration_config' ],
					'permission_callback' => [ $this, 'check_permissions' ],
				],
				'native-integrations/all'             => [
					'methods'             => 'GET',
					'callback'            => [ $this->services['config_manager'], 'get_all_integrations' ],
					'permission_callback' => [ $this, 'check_permissions' ],
				],
				'native-integrations/test'            => [
					'methods'             => 'POST',
					'callback'            => [ $this, 'test_integration_connection' ],
					'permission_callback' => [ $this, 'check_permissions' ],
				],
				'native-integrations/fields'          => [
					'methods'             => 'GET',
					'callback'            => [ $this->services['field_manager'], 'get_dynamic_fields' ],
					'permission_callback' => [ $this, 'check_permissions' ],
					'args'                => [
						'integration' => [
							'required' => true,
							'type'     => 'string',
						],
						'action'      => [
							'required' => true,
							'type'     => 'string',
						],
						'parameters'  => [
							'required' => false,
							'type'     => 'string',
						],
					],
				],
				'integrations/config/(?P<type>[a-zA-Z0-9_-]+)' => [
					'methods'             => 'GET',
					'callback'            => [ $this->services['config_manager'], 'get_integration_json_config' ],
					'permission_callback' => [ $this, 'check_permissions' ],
				],
				'native-integrations/test-workflow'   => [
					'methods'             => 'POST',
					'callback'            => [ $this->services['workflow_processor'], 'test_workflow' ],
					'permission_callback' => [ $this, 'check_permissions' ],
				],
				'native-integrations/oauth/authorize' => [
					'methods'             => 'POST',
					'callback'            => [ $this->services['oauth_handler'], 'handle_oauth_authorization' ],
					'permission_callback' => [ $this, 'check_permissions' ],
					'args'                => [
						'integration' => [
							'required' => true,
							'type'     => 'string',
						],
						'oauth_nonce' => [
							'required' => true,
							'type'     => 'string',
						],
					],
				],
				'native-integrations/oauth/callback-result' => [
					'methods'             => 'POST',
					'callback'            => [ $this->services['oauth_handler'], 'handle_oauth_callback_result' ],
					'permission_callback' => [ Integration_Utils::class, 'verify_oauth_callback' ],
					'args'                => [
						'integration_type'   => [
							'required' => true,
							'type'     => 'string',
						],
						'tokens'             => [
							'required' => true,
							'type'     => 'object',
						],
						'verification_token' => [
							'required' => false,
							'type'     => 'string',
						],
						'timestamp'          => [
							'required' => false,
							'type'     => 'integer',
						],
					],
				],
				'native-integrations/oauth/refresh'   => [
					'methods'             => 'POST',
					'callback'            => [ $this->services['oauth_handler'], 'handle_oauth_refresh' ],
					'permission_callback' => [ $this, 'check_permissions' ],
					'args'                => [
						'integration' => [
							'required' => true,
							'type'     => 'string',
						],
					],
				],
			]
		);
	}

	/**
	 * Check permissions for API endpoints
	 *
	 * @return bool True if user has permissions, false otherwise.
	 * @since 1.13.0
	 */
	public function check_permissions() {
		return current_user_can( 'manage_options' );
	}

	/**
	 * Test integration connection
	 *
	 * @param \WP_REST_Request $request The REST request.
	 * @return \WP_REST_Response
	 * @since 1.13.0
	 */
	public function test_integration_connection( $request ) {
		$nonce = sanitize_text_field( Helper::get_string_value( $request->get_header( 'X-WP-Nonce' ) ) );

		if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __( 'Invalid security token. Please refresh the page and try again.', 'sureforms-pro' ),
				],
				403
			);
		}

		$integration_name = $request->get_param( 'integration' );
		$credentials      = $request->get_param( 'credentials' );

		if ( empty( $integration_name ) ) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __( 'Integration name is required.', 'sureforms-pro' ),
				],
				400
			);
		}

		// Load integration configuration to get auth config.
		$integration_config = $this->services['config_manager']->load_integration_config( $integration_name );
		if ( ! $integration_config ) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __( 'Integration configuration not found.', 'sureforms-pro' ),
				],
				404
			);
		}

		$auth_config = $integration_config['auth'] ?? [];

		// Check if this is a WordPress plugin integration.
		$is_wordpress_plugin = isset( $integration_config['provider'] ) && 'wordpress' === $integration_config['provider']; // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled -- Configuration uses lowercase.

		if ( $is_wordpress_plugin ) {
			// For WordPress plugin integrations, test based on plugin activation.
			$plugin_detection = $integration_config['plugin_detection'] ?? [];

			$plugin_class    = $plugin_detection['class'] ?? '';
			$plugin_constant = $plugin_detection['constant'] ?? '';

			if ( empty( $plugin_class ) && empty( $plugin_constant ) ) {
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => __( 'Plugin detection configuration is missing.', 'sureforms-pro' ),
					],
					400
				);
			}

			$is_active = false;
			if ( ! empty( $plugin_class ) ) {
				$is_active = class_exists( $plugin_class );
			} elseif ( ! empty( $plugin_constant ) ) {
				$is_active = defined( $plugin_constant );
			}

			if ( $is_active ) {
				return new \WP_REST_Response(
					[
						'success' => true,
						'message' => sprintf(
							// translators: %s: Integration name.
							__( '%s plugin is active and ready for integration!', 'sureforms-pro' ),
							$integration_config['integration']['name'] ?? $integration_name
						),
					],
					200
				);
			}
				return new \WP_REST_Response(
					[
						'success' => false,
						'message' => sprintf(
							// translators: %s: Integration name.
							__( '%s plugin is not installed or not active.', 'sureforms-pro' ),
							$integration_config['integration']['name'] ?? $integration_name
						),
					],
					400
				);

		}

		// For regular API integrations, require credentials.
		if ( empty( $credentials ) ) {
			return new \WP_REST_Response(
				[
					'success' => false,
					'message' => __( 'Credentials are required for this integration.', 'sureforms-pro' ),
				],
				400
			);
		}

		return $this->services['connection_tester']->test_connection(
			$integration_name,
			$credentials,
			$auth_config
		);
	}

	/**
	 * Add native integrations meta field
	 *
	 * @since 1.13.0
	 * @return void
	 */
	public function add_native_integrations_meta() {
		register_post_meta(
			'sureforms_form',
			'_srfm_native_integrations',
			[
				'type'              => 'string',
				'single'            => true,
				'show_in_rest'      => [
					'schema' => [
						'type'    => 'string',
						'context' => [ 'edit' ],
					],
				],
				'auth_callback'     => static function() {
					return current_user_can( 'manage_options' );
				},
				'sanitize_callback' => [ $this, 'sanitize_native_integrations_meta' ],
			]
		);
	}

	/**
	 * Sanitize native integrations meta
	 *
	 * @param mixed $meta_value The meta value to sanitize.
	 * @return string Sanitized meta value.
	 * @since 1.13.0
	 */
	public function sanitize_native_integrations_meta( $meta_value ) {
		// Return empty string if no value.
		if ( empty( $meta_value ) ) {
			return '';
		}

		// Decode if it's a JSON string.
		if ( is_string( $meta_value ) ) {
			$data = json_decode( $meta_value, true );
			if ( json_last_error() !== JSON_ERROR_NONE ) {
				return '';
			}
		} else {
			$data = $meta_value;
		}

		// Ensure it's an array.
		if ( ! is_array( $data ) ) {
			return '';
		}

		$sanitized = [];

		// Sanitize each workflow.
		foreach ( $data as $workflow ) {
			$sanitized_workflow = [
				'id'               => isset( $workflow['id'] ) ? sanitize_text_field( $workflow['id'] ) : '',
				'name'             => isset( $workflow['name'] ) ? sanitize_text_field( $workflow['name'] ) : '',
				'status'           => isset( $workflow['status'] ) ? (bool) $workflow['status'] : true,
				'integration'      => isset( $workflow['integration'] ) ? sanitize_text_field( $workflow['integration'] ) : '',
				'action'           => isset( $workflow['action'] ) ? sanitize_text_field( $workflow['action'] ) : '',
				'connection'       => isset( $workflow['connection'] ) ? sanitize_text_field( $workflow['connection'] ) : '',
				'fields'           => [],
				'conditionalLogic' => Pro_helper::sanitize_conditional_logic( $workflow['conditionalLogic'] ?? [] ),
				'created_at'       => isset( $workflow['created_at'] ) ? absint( $workflow['created_at'] ) : time() * 1000,
				'updated_at'       => isset( $workflow['updated_at'] ) ? absint( $workflow['updated_at'] ) : time() * 1000,
				'run_count'        => isset( $workflow['run_count'] ) ? absint( $workflow['run_count'] ) : 0,
				'last_run'         => isset( $workflow['last_run'] ) ? absint( $workflow['last_run'] ) : null,
			];

			// Sanitize fields.
			if ( isset( $workflow['fields'] ) && is_array( $workflow['fields'] ) ) {
				foreach ( $workflow['fields'] as $key => $value ) {
					// Special handling for Notion integration to preserve property IDs with special characters.
					if ( isset( $workflow['integration'] ) && 'notion' === $workflow['integration'] ) {
						/**
						 * For Notion field keys, we need to preserve special characters like < > =
						 * Strip only control characters and null bytes for security.
						 * These keys are never output directly to HTML, only used as array keys.
						 *
						 * @since 2.4.0
						 */
						$sanitized_key = wp_kses( $key, [] );
						$sanitized_key = preg_replace( '/[\x00-\x1F\x7F]/u', '', $key );
						// Additionally strip any actual script tags for extra safety.
						$sanitized_key = preg_replace( '/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/mi', '', Helper::get_string_value( $sanitized_key ) );
					} else {
						// Standard sanitization for other integrations.
						$sanitized_key = sanitize_text_field( $key );
					}
					// Accept strings, numbers, and booleans.
					if ( is_string( $value ) ) {
						$sanitized_workflow['fields'][ $sanitized_key ] = Helper::get_string_value( $value );
					} elseif ( is_numeric( $value ) ) {
						$sanitized_workflow['fields'][ $sanitized_key ] = Helper::get_integer_value( $value );
					} elseif ( is_bool( $value ) ) {
						$sanitized_workflow['fields'][ $sanitized_key ] = (bool) $value;
					} else {
						$sanitized_workflow['fields'][ $sanitized_key ] = '';
					}
				}
			}

			$sanitized[] = $sanitized_workflow;
		}

		// Return as JSON string.
		$return = wp_json_encode( $sanitized );
		return $return ? $return : '';
	}

	/**
	 * Get filtered integrations data for frontend
	 *
	 * @return array Filtered integrations data.
	 * @since 1.13.0
	 */
	private function get_filtered_integrations_data() {
		// Create cache key based on available filter data.
		$additional_configs = apply_filters( 'srfm_pro_native_integrations_json_configs', [] );
		$cache_key          = 'srfm_pro_filtered_integrations_' . md5( Helper::get_string_value( wp_json_encode( $additional_configs ) ) );
		$cached_data        = wp_cache_get( $cache_key, 'sureforms_pro' );

		if ( false !== $cached_data && is_array( $cached_data ) ) {
			return $cached_data;
		}

		// Use new distributed loading system.
		$data = $this->services['config_manager']->get_all_integrations_data();

		// Apply filter to include third-party integrations.
		$data = $this->services['config_manager']->apply_integration_filters( $data );

		// Cache for 1 hour.
		wp_cache_set( $cache_key, $data, 'sureforms_pro', HOUR_IN_SECONDS );

		return $data;
	}

	/**
	 * Initialize service instances
	 *
	 * @since 1.13.0
	 * @return void
	 */
	private function init_services() {
		// Load core native integration classes first to avoid fatal errors.
		$this->load_provider_classes();

		// Initialize services with dependencies.
		$this->services['config_manager']     = new Config_Manager();
		$this->services['oauth_handler']      = new OAuth_Handler( $this->services['config_manager'] );
		$this->services['connection_tester']  = new Connection_Tester( $this->services['oauth_handler'] );
		$this->services['field_manager']      = new Field_Manager( $this->services['config_manager'] );
		$this->services['workflow_processor'] = new Workflow_Processor( $this->services['config_manager'], $this->services['oauth_handler'] );
	}

	/**
	 * Load core native integration classes
	 *
	 * @since 1.13.0
	 * @return void
	 */
	private function load_provider_classes() {
		$core_classes = [
			'integration-provider.php',
			'generic-provider.php',
			'wordpress-provider.php',
			'wordpress-action.php',
			'provider-factory.php',
			'oauth-handler.php',
		];

		foreach ( $core_classes as $class_file ) {
			require_once __DIR__ . '/native-integrations/' . $class_file;
		}
	}

	/**
	 * Register WordPress plugin handlers for native integrations
	 *
	 * @since 1.13.0
	 * @return void
	 */
	private function register_plugin_handlers() {
		// Define available plugin integrations.
		$plugin_integrations = [
			'latepoint'   => [
				'file'      => __DIR__ . '/native-integrations/integrations/latepoint/actions.php',
				'detection' => [ 'class' => 'OsBookingModel' ],
			],
			'fluentcrm'   => [
				'file'      => __DIR__ . '/native-integrations/integrations/fluentcrm/actions.php',
				'detection' => [ 'constant' => 'FLUENTCRM' ],
			],
			'mailpoet'    => [
				'file'      => __DIR__ . '/native-integrations/integrations/mailpoet/actions.php',
				'detection' => [ 'class' => '\\MailPoet\\Config\\Activator' ],
			],
			'mailerpress' => [
				'file'      => __DIR__ . '/native-integrations/integrations/mailerpress/actions.php',
				'detection' => [ 'constant' => 'MAILERPRESS_VERSION' ],
			],
		];

		// Allow third-party plugins to register their integrations.
		$plugin_integrations = apply_filters( 'srfm_pro_wordpress_plugin_integrations', $plugin_integrations );

		foreach ( $plugin_integrations as $plugin_slug => $config ) {
			// Check plugin detection.
			$is_active = false;
			$detection = $config['detection'] ?? [];

			if ( isset( $detection['class'] ) ) {
				$is_active = class_exists( $detection['class'] );
			} elseif ( isset( $detection['constant'] ) ) {
				$is_active = defined( $detection['constant'] );
			} elseif ( is_string( $detection ) ) {
				// Backward compatibility for old format.
				$is_active = class_exists( $detection );
			}

			if ( ! $is_active ) {
				continue;
			}

			// Check if the integration file exists.
			if ( ! file_exists( $config['file'] ) ) {
				continue;
			}

			try {
				// Load the integration file.
				require_once $config['file'];

				// Call register_filters function if it exists.
				$register_function = '\\SRFM_Pro\\Inc\\Pro\\Native_Integrations\\Integrations\\' . ucfirst( $plugin_slug ) . '\\register_filters';
				if ( function_exists( $register_function ) ) {
					call_user_func( $register_function );
				}
			} catch ( \Exception $e ) {
				_doing_it_wrong( __METHOD__, 'Native integrations initialization error: ' . esc_html( $e->getMessage() ), '1.0.0' );
			}
		}
	}

	/**
	 * Enqueue scripts
	 *
	 * @since 1.13.0
	 * @return void
	 */
	private function enqueue_scripts() {
		$scripts = [
			[
				'unique_file'        => 'nativeIntegrations',
				'unique_handle'      => 'native-integrations',
				'extra_dependencies' => [],
			],
		];

		foreach ( $scripts as $script ) {
			$script_dep_path = SRFM_PRO_DIR . 'dist/package/pro/' . $script['unique_file'] . '.asset.php';
			$script_dep_data = file_exists( $script_dep_path )
				? include $script_dep_path
				: [
					'dependencies' => [],
					'version'      => SRFM_PRO_VER,
				];

			// Ensure dependencies are arrays.
			$script_dep = array_merge(
				is_array( $script_dep_data['dependencies'] ) ? $script_dep_data['dependencies'] : [],
				is_array( $script['extra_dependencies'] ) ? $script['extra_dependencies'] : []
			);

			// Enqueue script.
			wp_enqueue_script(
				SRFM_PRO_SLUG . '-' . $script['unique_handle'], // Handle.
				SRFM_PRO_URL . 'dist/package/pro/' . $script['unique_file'] . '.js',
				$script_dep, // Dependencies.
				$script_dep_data['version'], // Version.
				true // Enqueue in footer.
			);

			// Register script translations.
			Pro_Helper::register_script_translations( SRFM_PRO_SLUG . '-' . $script['unique_handle'] );

			// Localize filtered integrations data.
			if ( 'native-integrations' === $script['unique_handle'] ) {
				$filtered_data = $this->get_filtered_integrations_data();

				// Add icons path, middleware URL and OAuth nonce to localized data.
				$localized_data = array_merge(
					$filtered_data,
					[
						'icons_path'     => SRFM_PRO_URL . 'inc/pro/native-integrations/integrations/icons/',
						'middleware_url' => defined( 'SRFM_MIDDLEWARE_BASE_URL' ) ? SRFM_MIDDLEWARE_BASE_URL . 'integrations/' : '',
						'oauth_nonce'    => wp_create_nonce( 'srfm_oauth_authorize' ),
					]
				);

				wp_localize_script(
					SRFM_PRO_SLUG . '-' . $script['unique_handle'],
					'srfm_pro_native_integrations',
					$localized_data
				);
			}
		}
	}

}
