<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

if ( ! class_exists( 'SftcyWordformConnectSalesforce' ) ) {
	class SftcyWordformConnectSalesforce {
		private static $initiated = false;
		public static $output     = [];
		public static $configure_spinning_icon = '<i class="fa-solid fa-gear fa-spin"></i>';

		public function __construct() {
			if ( ! self::$initiated ) {
				self::initiate_hooks();
			}
		}

		private static function initiate_hooks() {
			add_action( 'wp_ajax_wordform_connect_save_salesforce_auth_credentials_with_authentication', [ __CLASS__, 'wordform_connect_save_salesforce_auth_credentials_with_authentication' ] );
			add_action( 'wp_ajax_wordform_connect_create_salesforce_with_form_fields', [ __CLASS__, 'wordform_connect_create_salesforce_with_form_fields' ] );
			self::$initiated = true;
		}

		public static function get_salesforce_credentials() {
			$managed_credentials = self::get_managed_salesforce_credentials();
			if ( $managed_credentials ) {
				return $managed_credentials;
			}

			$credentials = get_option( 'wordform_connect_salesforce_credentials', [] );
			if ( isset( $credentials['clientID'], $credentials['clientSecret'], $credentials['loginUrl'], $credentials['clientRedirectUrl'] ) && ! empty( $credentials['clientID'] ) && ! empty( $credentials['clientSecret'] ) && ! empty( $credentials['loginUrl'] ) && ! empty( $credentials['clientRedirectUrl'] ) ) {
				return [
					'clientID'         => $credentials['clientID'],
					'clientSecret'     => $credentials['clientSecret'],
					'loginUrl'         => untrailingslashit( $credentials['loginUrl'] ),
					'clientRedirectUrl'=> $credentials['clientRedirectUrl'],
				];
			}

			return [];
		}

		/**
		 * Get centrally managed Salesforce OAuth credentials supplied by the plugin owner.
		 *
		 * @return array
		 */
		public static function get_managed_salesforce_credentials() {
			$managed_credentials = apply_filters(
				'wordform_connect_salesforce_managed_oauth_credentials',
				[
					'clientID'          => defined( 'WORDFORM_CONNECT_SALESFORCE_CLIENT_ID' ) ? WORDFORM_CONNECT_SALESFORCE_CLIENT_ID : '',
					'clientSecret'      => defined( 'WORDFORM_CONNECT_SALESFORCE_CLIENT_SECRET' ) ? WORDFORM_CONNECT_SALESFORCE_CLIENT_SECRET : '',
					'loginUrl'          => defined( 'WORDFORM_CONNECT_SALESFORCE_LOGIN_URL' ) ? WORDFORM_CONNECT_SALESFORCE_LOGIN_URL : 'https://login.salesforce.com',
					'clientRedirectUrl' => SftcyWordformConnectBase::get_wordform_connect_oauth_redirect_url(),
				]
			);

			if ( isset( $managed_credentials['clientID'], $managed_credentials['clientSecret'], $managed_credentials['loginUrl'], $managed_credentials['clientRedirectUrl'] ) && ! empty( $managed_credentials['clientID'] ) && ! empty( $managed_credentials['clientSecret'] ) && ! empty( $managed_credentials['loginUrl'] ) && ! empty( $managed_credentials['clientRedirectUrl'] ) ) {
				return [
					'clientID'          => sanitize_text_field( $managed_credentials['clientID'] ),
					'clientSecret'      => sanitize_text_field( $managed_credentials['clientSecret'] ),
					'loginUrl'          => esc_url_raw( untrailingslashit( $managed_credentials['loginUrl'] ) ),
					'clientRedirectUrl' => esc_url_raw( $managed_credentials['clientRedirectUrl'] ),
				];
			}

			return [];
		}

		/**
		 * Check whether managed one-click Salesforce credentials are available.
		 *
		 * @return bool
		 */
		public static function is_salesforce_managed_oauth_available() {
			return ! empty( self::get_managed_salesforce_credentials() );
		}

		/**
		 * Build Salesforce OAuth authorization URL for one-click connect flow.
		 *
		 * @return string
		 */
		public static function get_salesforce_authorization_uri() {
			$credentials = self::get_salesforce_credentials();
			if ( ! $credentials ) {
				return '';
			}

			$redirect_params = [
				'response_type' => 'code',
				'client_id'     => $credentials['clientID'],
				'redirect_uri'  => $credentials['clientRedirectUrl'],
				'scope'         => 'api refresh_token',
				'state'         => 'salesforce',
			];

			return untrailingslashit( $credentials['loginUrl'] ) . '/services/oauth2/authorize?' . http_build_query( $redirect_params );
		}

		public static function get_salesforce_token_info() {
			$token_info = get_option( 'wordform_connect_salesforce_token', [] );
			return is_array( $token_info ) ? $token_info : [];
		}

		public static function wordform_connect_save_salesforce_auth_credentials_with_authentication() {
			check_ajax_referer( 'scwordform_wpnonce', 'security' );

			self::$output = [];
			$client_id     = isset( $_POST['params']['salesforceClientId'] ) ? sanitize_text_field( trim( $_POST['params']['salesforceClientId'] ) ) : '';
			$client_secret = isset( $_POST['params']['salesforceClientSecret'] ) ? sanitize_text_field( trim( $_POST['params']['salesforceClientSecret'] ) ) : '';
			$login_url     = isset( $_POST['params']['salesforceLoginUrl'] ) ? esc_url_raw( trim( $_POST['params']['salesforceLoginUrl'] ) ) : '';
			$redirect_url  = isset( $_POST['params']['salesforceRedirectUrl'] ) ? esc_url_raw( trim( $_POST['params']['salesforceRedirectUrl'] ) ) : '';

			if ( empty( $client_id ) || empty( $client_secret ) || empty( $login_url ) || empty( $redirect_url ) ) {
				self::$output['status']  = 'fail';
				self::$output['reason']  = 'Salesforce credential values are missing.';
				self::$output['comment'] = 'Salesforce Consumer Key, Consumer Secret, Login URL, and Redirect URL are required.';
			} elseif ( ! filter_var( $login_url, FILTER_VALIDATE_URL ) || ! filter_var( $redirect_url, FILTER_VALIDATE_URL ) ) {
				self::$output['status']  = 'fail';
				self::$output['reason']  = 'Salesforce URLs are invalid.';
				self::$output['comment'] = 'Salesforce Login URL or Redirect URL is not valid.';
			} else {
				$credentials = [
					'clientID'          => $client_id,
					'clientSecret'      => $client_secret,
					'loginUrl'          => untrailingslashit( $login_url ),
					'clientRedirectUrl' => $redirect_url,
				];

				$redirect_params = [
					'response_type' => 'code',
					'client_id'     => $client_id,
					'redirect_uri'  => $redirect_url,
					'scope'         => 'api refresh_token',
					'state'         => 'salesforce',
				];
				self::$output['authRedirectUri'] = untrailingslashit( $login_url ) . '/services/oauth2/authorize?' . http_build_query( $redirect_params );

				if ( update_option( 'wordform_connect_salesforce_credentials', $credentials ) ) {
					self::$output['status']  = 'success';
					self::$output['reason']  = 'Salesforce credentials saved.';
					self::$output['comment'] = self::$configure_spinning_icon . ' Salesforce credentials saved. Redirecting to Salesforce for authorization...';
				} else {
					self::$output['status']  = 'warning';
					self::$output['reason']  = 'Salesforce credentials did not change.';
					self::$output['comment'] = self::$configure_spinning_icon . ' Salesforce credentials saved. Redirecting to Salesforce for authorization...';
				}
			}

			echo wp_json_encode( self::$output, JSON_HEX_APOS );
			wp_die();
		}

		public static function wordform_connect_configure_salesforce_authentication( $code = null ) {
			$credentials = self::get_salesforce_credentials();
			if ( is_null( $code ) || ! $credentials ) {
				SftcyWordformConnectBase::log_connection_configuration_event( 'salesforce', 'oauth_callback', 'Salesforce authorization code or credentials are missing.', array(), 'error' );
				update_option( 'wordform_connect_salesforce_last_auth_error', 'Salesforce authorization code or credentials are missing.' );
				return false;
			}

			$response = wp_remote_post(
				$credentials['loginUrl'] . '/services/oauth2/token',
				[
					'timeout' => 20,
					'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded' ],
					'body'    => [
						'grant_type'    => 'authorization_code',
						'code'          => $code,
						'client_id'     => $credentials['clientID'],
						'client_secret' => $credentials['clientSecret'],
						'redirect_uri'  => $credentials['clientRedirectUrl'],
					],
				]
			);

			if ( is_wp_error( $response ) ) {
				SftcyWordformConnectBase::log_connection_configuration_event( 'salesforce', 'oauth_callback', $response->get_error_message(), array(), 'error' );
				update_option( 'wordform_connect_salesforce_last_auth_error', $response->get_error_message() );
				return false;
			}

			$response_body = wp_remote_retrieve_body( $response );
			$response_data = json_decode( $response_body, true );
			if ( ! is_array( $response_data ) || empty( $response_data['access_token'] ) || empty( $response_data['refresh_token'] ) || empty( $response_data['instance_url'] ) ) {
				$error_message = SftcyWordformConnectBase::extract_connect_remote_error_message( $response_body );
				SftcyWordformConnectBase::log_connection_configuration_event( 'salesforce', 'oauth_callback', ! empty( $error_message ) ? $error_message : 'Salesforce did not return a valid access token.', array(), 'error' );
				update_option( 'wordform_connect_salesforce_last_auth_error', ! empty( $error_message ) ? $error_message : 'Salesforce did not return a valid access token.' );
				return false;
			}

			$api_version = self::fetch_salesforce_latest_api_version( $response_data['instance_url'], $response_data['access_token'] );
			$token_info  = [
				'access_token'             => $response_data['access_token'],
				'refresh_token'            => $response_data['refresh_token'],
				'instance_url'             => untrailingslashit( $response_data['instance_url'] ),
				'api_version'              => $api_version,
				'tokeninfo_updated_datetime' => current_time( 'mysql' ),
			];

			update_option( 'wordform_connect_salesforce_token', $token_info );
			$is_saved = self::save_configured_salesforce_application();
			if ( ! $is_saved ) {
				SftcyWordformConnectBase::log_connection_configuration_event( 'salesforce', 'oauth_callback', 'Salesforce token was received, but WordForm could not save the configured application state.', array(), 'error' );
				update_option( 'wordform_connect_salesforce_last_auth_error', 'Salesforce token was received, but WordForm could not save the configured application state.' );
				return false;
			}

			delete_option( 'wordform_connect_salesforce_last_auth_error' );
			return true;
		}

		public static function fetch_salesforce_latest_api_version( $instance_url = '', $access_token = '' ) {
			if ( empty( $instance_url ) || empty( $access_token ) ) {
				return 'v60.0';
			}

			$response = wp_remote_get(
				untrailingslashit( $instance_url ) . '/services/data/',
				[
					'timeout' => 20,
					'headers' => [ 'Authorization' => 'Bearer ' . $access_token ],
				]
			);
			if ( is_wp_error( $response ) ) {
				return 'v60.0';
			}

			$response_data = json_decode( wp_remote_retrieve_body( $response ), true );
			if ( is_array( $response_data ) && ! empty( $response_data ) ) {
				$last_version = end( $response_data );
				if ( is_array( $last_version ) && isset( $last_version['version'] ) && ! empty( $last_version['version'] ) ) {
					return 'v' . sanitize_text_field( (string) $last_version['version'] );
				}
			}

			return 'v60.0';
		}

		public static function save_configured_salesforce_application() {
			$application_slug = 'salesforce';
			$application_name = 'Salesforce';
			$data             = [ 'application_slug' => $application_slug, 'application_name' => $application_name ];

			global $wpdb;
			$table         = $wpdb->prefix . SftcyWordformBase::$sc_wordform_configured_application_tbl;
			$query_results = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE application_slug = %s LIMIT 1', [ $table, $application_slug ] ), ARRAY_A );

			$data['configured_info'] = wp_json_encode( [ 'reconfigured' => $query_results ? 'yes' : 'no', 'oauthProvider' => 'salesforce' ] );

			if ( $query_results ) {
				$update_result = $wpdb->update( $table, array_merge( $data, [ 'configured_status' => 'active' ] ), [ 'id' => $query_results[0]['id'] ] );
				return false !== $update_result;
			}

			return false !== $wpdb->insert( $table, $data );
		}

		/**
		 * Check whether Salesforce re-authorization is required.
		 *
		 * @return bool
		 */
		public static function is_salesforce_authentication_required() {
			$token_info = self::get_salesforce_token_info();
			if ( empty( $token_info['refresh_token'] ) || empty( $token_info['instance_url'] ) ) {
				return true;
			}

			return false;
		}

		public static function refresh_salesforce_access_token() {
			$credentials = self::get_salesforce_credentials();
			$token_info  = self::get_salesforce_token_info();
			if ( ! $credentials || empty( $token_info['refresh_token'] ) ) {
				return false;
			}

			$response = wp_remote_post(
				$credentials['loginUrl'] . '/services/oauth2/token',
				[
					'timeout' => 20,
					'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded' ],
					'body'    => [
						'grant_type'    => 'refresh_token',
						'refresh_token' => $token_info['refresh_token'],
						'client_id'     => $credentials['clientID'],
						'client_secret' => $credentials['clientSecret'],
					],
				]
			);
			if ( is_wp_error( $response ) ) {
				return false;
			}

			$response_data = json_decode( wp_remote_retrieve_body( $response ), true );
			if ( ! is_array( $response_data ) || empty( $response_data['access_token'] ) ) {
				return false;
			}

			$new_info = $token_info;
			$new_info['access_token'] = $response_data['access_token'];
			if ( ! empty( $response_data['instance_url'] ) ) {
				$new_info['instance_url'] = untrailingslashit( $response_data['instance_url'] );
			}
			if ( empty( $new_info['api_version'] ) ) {
				$new_info['api_version'] = self::fetch_salesforce_latest_api_version( $new_info['instance_url'], $new_info['access_token'] );
			}
			$new_info['tokeninfo_updated_datetime'] = current_time( 'mysql' );
			update_option( 'wordform_connect_salesforce_token', $new_info );

			return $new_info['access_token'];
		}

		public static function get_salesforce_access_token() {
			$token_info = self::get_salesforce_token_info();
			if ( ! empty( $token_info['access_token'] ) ) {
				return $token_info['access_token'];
			}

			return self::refresh_salesforce_access_token();
		}

		public static function wordform_connect_create_salesforce_with_form_fields() {
			check_ajax_referer( 'scwordform_wpnonce', 'security' );
			self::$output = [];

			if ( isset( $_POST['params'] ) && array_filter( $_POST['params'] ) ) {
				$wordform_id               = isset( $_POST['params']['wordFormID'] ) ? sanitize_text_field( $_POST['params']['wordFormID'] ) : '';
				$wordform_name             = isset( $_POST['params']['wordFormName'] ) ? sanitize_text_field( $_POST['params']['wordFormName'] ) : '';
				$configured_application_id = isset( $_POST['params']['applicationID'] ) ? absint( $_POST['params']['applicationID'] ) : 0;
				$configured_application_name = isset( $_POST['params']['applicationName'] ) ? sanitize_text_field( $_POST['params']['applicationName'] ) : '';

				if ( ! empty( $wordform_id ) && $configured_application_id > 0 ) {
					$form_fields = SftcyWordformBuildForm::wordform_get_field_names( $wordform_id );
					$token_info  = self::get_salesforce_token_info();
					if ( $form_fields && array_filter( $form_fields ) && ! empty( $token_info['refresh_token'] ) ) {
						$connection_info = [
							'applicationName'     => $configured_application_name,
							'formName'            => $wordform_name,
							'formFields'          => $form_fields,
							'payloadFormat'       => 'salesforce-contact',
							'connectionUpdatedAt' => current_time( 'mysql' ),
						];
						$db_result = SftcyWordformConnectBase::wordform_save_connected_application_info(
							[
								'configured_application_tbl_id' => $configured_application_id,
								'wordform_id'                   => $wordform_id,
								'connection_info'               => wp_json_encode( $connection_info ),
							]
						);

						if ( false !== $db_result ) {
							self::$output['status']  = 'success';
							self::$output['reason']  = 'Salesforce connected successfully.';
							self::$output['comment'] = 'Salesforce connected successfully.';
						} else {
							self::$output['status']  = 'fail';
							self::$output['reason']  = 'Connection info storing failed.';
							self::$output['comment'] = 'Could not create Salesforce connection record.';
						}
					} else {
						self::$output['status']  = 'fail';
						self::$output['reason']  = 'Salesforce authorization not completed.';
						self::$output['comment'] = 'Please complete Salesforce authorization first.';
					}
				} else {
					self::$output['status']  = 'fail';
					self::$output['reason']  = 'Required connection values missing.';
					self::$output['comment'] = 'WordForm ID or configured application ID not found.';
				}
			} else {
				self::$output['status']  = 'fail';
				self::$output['reason']  = 'Post parameters are missing.';
				self::$output['comment'] = 'Required post parameters are missing.';
			}

			echo wp_json_encode( self::$output, JSON_HEX_AMP );
			wp_die();
		}

		public static function wordform_send_forms_data_into_salesforce( $forms_data = [] ) {
			$send_info                    = [];
			$send_info['applicationSlug'] = 'salesforce';

			$access_token  = self::get_salesforce_access_token();
			$token_info    = self::get_salesforce_token_info();
			$instance_url  = isset( $token_info['instance_url'] ) ? untrailingslashit( $token_info['instance_url'] ) : '';
			$api_version   = isset( $token_info['api_version'] ) ? $token_info['api_version'] : 'v60.0';
			if ( empty( $access_token ) || empty( $instance_url ) ) {
				$send_info['status']  = 'fail';
				$send_info['reason']  = 'Salesforce access token or instance URL missing.';
				$send_info['comment'] = 'Salesforce authorization is incomplete.';
				return $send_info;
			}

			$contact_properties = SftcyWordformConnectBase::extract_common_contact_properties_from_submission_fields( $forms_data );
			if ( empty( $contact_properties['email'] ) ) {
				$send_info['status']  = 'fail';
				$send_info['reason']  = 'Email field value not found in this form submission.';
				$send_info['comment'] = 'Salesforce requires at least one valid email field in the connected form.';
				return $send_info;
			}

			$last_name = ! empty( $contact_properties['lastName'] ) ? $contact_properties['lastName'] : sanitize_text_field( current( explode( '@', $contact_properties['email'] ) ) );
			$salesforce_fields = [
				'Email'    => $contact_properties['email'],
				'LastName' => $last_name,
			];
			if ( ! empty( $contact_properties['firstName'] ) ) {
				$salesforce_fields['FirstName'] = $contact_properties['firstName'];
			}
			if ( ! empty( $contact_properties['phone'] ) ) {
				$salesforce_fields['Phone'] = $contact_properties['phone'];
			}

			$headers = [
				'Authorization' => 'Bearer ' . $access_token,
				'Content-Type'  => 'application/json; charset=utf-8',
			];

			$query_url = $instance_url . '/services/data/' . $api_version . '/query?q=' . rawurlencode( "SELECT Id FROM Contact WHERE Email = '" . str_replace( "'", "\\'", $contact_properties['email'] ) . "' LIMIT 1" );
			$query_response = wp_remote_get( $query_url, [ 'timeout' => 20, 'headers' => $headers ] );
			if ( is_wp_error( $query_response ) ) {
				$send_info['status']       = 'fail';
				$send_info['reason']       = 'Salesforce contact lookup failed.';
				$send_info['requestError'] = $query_response->get_error_message();
				$send_info['comment']      = 'Salesforce contact lookup request could not be completed.';
				return $send_info;
			}

			$query_status = (int) wp_remote_retrieve_response_code( $query_response );
			if ( 401 === $query_status ) {
				$access_token = self::refresh_salesforce_access_token();
				if ( ! empty( $access_token ) ) {
					$headers['Authorization'] = 'Bearer ' . $access_token;
					$query_response = wp_remote_get( $query_url, [ 'timeout' => 20, 'headers' => $headers ] );
					$query_status   = (int) wp_remote_retrieve_response_code( $query_response );
				}
			}

			$query_data = json_decode( wp_remote_retrieve_body( $query_response ), true );
			$contact_id = '';
			if ( 200 === $query_status && is_array( $query_data ) && ! empty( $query_data['records'][0]['Id'] ) ) {
				$contact_id = sanitize_text_field( $query_data['records'][0]['Id'] );
			}

			$request_args = [
				'timeout' => 20,
				'headers' => $headers,
				'body'    => wp_json_encode( $salesforce_fields ),
			];
			if ( ! empty( $contact_id ) ) {
				$response = wp_remote_request( $instance_url . '/services/data/' . $api_version . '/sobjects/Contact/' . rawurlencode( $contact_id ), array_merge( $request_args, [ 'method' => 'PATCH' ] ) );
				$send_info['operation'] = 'update';
				$send_info['contactId'] = $contact_id;
			} else {
				$response = wp_remote_post( $instance_url . '/services/data/' . $api_version . '/sobjects/Contact/', $request_args );
				$send_info['operation'] = 'create';
			}

			if ( is_wp_error( $response ) ) {
				$send_info['status']       = 'fail';
				$send_info['reason']       = 'Salesforce contact sync failed.';
				$send_info['requestError'] = $response->get_error_message();
				$send_info['comment']      = 'Salesforce contact request could not be completed.';
				return $send_info;
			}

			$status_code = (int) wp_remote_retrieve_response_code( $response );
			$response_body = wp_remote_retrieve_body( $response );
			$response_data = json_decode( $response_body, true );
			$send_info['responseStatusCode'] = $status_code;

			if ( $status_code >= 200 && $status_code < 300 ) {
				$send_info['status']  = 'success';
				$send_info['reason']  = 'Form submission data sent to Salesforce.';
				$send_info['comment'] = 'Salesforce contact synced successfully.';
				if ( is_array( $response_data ) && ! empty( $response_data['id'] ) ) {
					$send_info['contactId'] = sanitize_text_field( $response_data['id'] );
				}
			} else {
				$send_info['status']  = 'fail';
				$send_info['reason']  = 'Salesforce response status indicates failure.';
				$send_info['comment'] = 'Salesforce API returned non-success HTTP status.';
				$send_info['responseBody'] = substr( sanitize_textarea_field( (string) $response_body ), 0, 500 );
			}

			return $send_info;
		}

		public static function is_salesforce_configured_status_active() {
			global $wpdb;
			$table         = $wpdb->prefix . SftcyWordformBase::$sc_wordform_configured_application_tbl;
			$query_results = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE application_slug = %s AND configured_status = %s LIMIT 1', [ $table, 'salesforce', 'active' ] ), ARRAY_A );
			return ! empty( $query_results );
		}
	}
}
