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

if ( ! class_exists( 'SftcyWordformConnectZohocrm' ) ) {
	class SftcyWordformConnectZohocrm {
		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_zohocrm_auth_credentials_with_authentication', [ __CLASS__, 'wordform_connect_save_zohocrm_auth_credentials_with_authentication' ] );
			add_action( 'wp_ajax_wordform_connect_create_zohocrm_with_form_fields', [ __CLASS__, 'wordform_connect_create_zohocrm_with_form_fields' ] );
			self::$initiated = true;
		}

		public static function get_zohocrm_credentials() {
			$managed_credentials = self::get_managed_zohocrm_credentials();
			if ( $managed_credentials ) {
				return $managed_credentials;
			}

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

			return [];
		}

		/**
		 * Get centrally managed Zoho CRM OAuth credentials supplied by the plugin owner.
		 *
		 * @return array
		 */
		public static function get_managed_zohocrm_credentials() {
			$managed_credentials = apply_filters(
				'wordform_connect_zohocrm_managed_oauth_credentials',
				[
					'clientID'          => defined( 'WORDFORM_CONNECT_ZOHOCRM_CLIENT_ID' ) ? WORDFORM_CONNECT_ZOHOCRM_CLIENT_ID : '',
					'clientSecret'      => defined( 'WORDFORM_CONNECT_ZOHOCRM_CLIENT_SECRET' ) ? WORDFORM_CONNECT_ZOHOCRM_CLIENT_SECRET : '',
					'accountsUrl'       => defined( 'WORDFORM_CONNECT_ZOHOCRM_ACCOUNTS_URL' ) ? WORDFORM_CONNECT_ZOHOCRM_ACCOUNTS_URL : 'https://accounts.zoho.com',
					'clientRedirectUrl' => SftcyWordformConnectBase::get_wordform_connect_oauth_redirect_url(),
				]
			);

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

			return [];
		}

		/**
		 * Check whether managed one-click Zoho CRM credentials are available.
		 *
		 * @return bool
		 */
		public static function is_zohocrm_managed_oauth_available() {
			return ! empty( self::get_managed_zohocrm_credentials() );
		}

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

			$redirect_params = [
				'scope'         => 'ZohoCRM.modules.contacts.ALL',
				'client_id'     => $credentials['clientID'],
				'response_type' => 'code',
				'access_type'   => 'offline',
				'prompt'        => 'consent',
				'redirect_uri'  => $credentials['clientRedirectUrl'],
				'state'         => 'zohocrm',
			];

			return untrailingslashit( $credentials['accountsUrl'] ) . '/oauth/v2/auth?' . http_build_query( $redirect_params );
		}

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

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

			self::$output = [];
			$client_id     = isset( $_POST['params']['zohocrmClientId'] ) ? sanitize_text_field( trim( $_POST['params']['zohocrmClientId'] ) ) : '';
			$client_secret = isset( $_POST['params']['zohocrmClientSecret'] ) ? sanitize_text_field( trim( $_POST['params']['zohocrmClientSecret'] ) ) : '';
			$accounts_url  = isset( $_POST['params']['zohocrmAccountsUrl'] ) ? esc_url_raw( trim( $_POST['params']['zohocrmAccountsUrl'] ) ) : '';
			$redirect_url  = isset( $_POST['params']['zohocrmRedirectUrl'] ) ? esc_url_raw( trim( $_POST['params']['zohocrmRedirectUrl'] ) ) : '';

			if ( empty( $client_id ) || empty( $client_secret ) || empty( $accounts_url ) || empty( $redirect_url ) ) {
				self::$output['status']  = 'fail';
				self::$output['reason']  = 'Zoho CRM credential values are missing.';
				self::$output['comment'] = 'Zoho CRM Client ID, Client Secret, Accounts URL, and Redirect URL are required.';
			} elseif ( ! filter_var( $accounts_url, FILTER_VALIDATE_URL ) || ! filter_var( $redirect_url, FILTER_VALIDATE_URL ) ) {
				self::$output['status']  = 'fail';
				self::$output['reason']  = 'Zoho CRM URLs are invalid.';
				self::$output['comment'] = 'Zoho CRM Accounts URL or Redirect URL is not valid.';
			} else {
				$credentials = [
					'clientID'          => $client_id,
					'clientSecret'      => $client_secret,
					'accountsUrl'       => untrailingslashit( $accounts_url ),
					'clientRedirectUrl' => $redirect_url,
				];

				$redirect_params = [
					'scope'         => 'ZohoCRM.modules.contacts.ALL',
					'client_id'     => $client_id,
					'response_type' => 'code',
					'access_type'   => 'offline',
					'prompt'        => 'consent',
					'redirect_uri'  => $redirect_url,
					'state'         => 'zohocrm',
				];
				self::$output['authRedirectUri'] = untrailingslashit( $accounts_url ) . '/oauth/v2/auth?' . http_build_query( $redirect_params );

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

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

		public static function wordform_connect_configure_zohocrm_authentication( $code = null ) {
			$credentials = self::get_zohocrm_credentials();
			if ( is_null( $code ) || ! $credentials ) {
				SftcyWordformConnectBase::log_connection_configuration_event( 'zohocrm', 'oauth_callback', 'Zoho CRM authorization code or credentials are missing.', array(), 'error' );
				update_option( 'wordform_connect_zohocrm_last_auth_error', 'Zoho CRM authorization code or credentials are missing.' );
				return false;
			}

			$response = wp_remote_post(
				$credentials['accountsUrl'] . '/oauth/v2/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( 'zohocrm', 'oauth_callback', $response->get_error_message(), array(), 'error' );
				update_option( 'wordform_connect_zohocrm_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['api_domain'] ) ) {
				$error_message = SftcyWordformConnectBase::extract_connect_remote_error_message( $response_body );
				SftcyWordformConnectBase::log_connection_configuration_event( 'zohocrm', 'oauth_callback', ! empty( $error_message ) ? $error_message : 'Zoho CRM did not return a valid access token.', array(), 'error' );
				update_option( 'wordform_connect_zohocrm_last_auth_error', ! empty( $error_message ) ? $error_message : 'Zoho CRM did not return a valid access token.' );
				return false;
			}

			$current_timestamp = time();
			$expires_in        = isset( $response_data['expires_in'] ) ? absint( $response_data['expires_in'] ) : 3600;
			$token_info        = [
				'access_token'                => $response_data['access_token'],
				'refresh_token'               => $response_data['refresh_token'],
				'api_domain'                  => untrailingslashit( $response_data['api_domain'] ),
				'access_token_expire_datetime'=> date( 'Y-m-d H:i:s', $current_timestamp + $expires_in ),
				'tokeninfo_updated_datetime'  => current_time( 'mysql' ),
			];

			update_option( 'wordform_connect_zohocrm_token', $token_info );
			$is_saved = self::save_configured_zohocrm_application();
			if ( ! $is_saved ) {
				SftcyWordformConnectBase::log_connection_configuration_event( 'zohocrm', 'oauth_callback', 'Zoho CRM token was received, but WordForm could not save the configured application state.', array(), 'error' );
				update_option( 'wordform_connect_zohocrm_last_auth_error', 'Zoho CRM token was received, but WordForm could not save the configured application state.' );
				return false;
			}

			delete_option( 'wordform_connect_zohocrm_last_auth_error' );
			return true;
		}

		public static function save_configured_zohocrm_application() {
			$application_slug = 'zohocrm';
			$application_name = 'Zoho CRM';
			$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' => 'zohocrm' ] );

			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 Zoho CRM re-authorization is required.
		 *
		 * @return bool
		 */
		public static function is_zohocrm_authentication_required() {
			$token_info = self::get_zohocrm_token_info();
			if ( empty( $token_info['refresh_token'] ) || empty( $token_info['api_domain'] ) ) {
				return true;
			}

			return false;
		}

		public static function is_zohocrm_access_token_expired() {
			$token_info = self::get_zohocrm_token_info();
			if ( ! empty( $token_info['access_token_expire_datetime'] ) ) {
				$current_datetime = new DateTime( 'now' );
				$expire_datetime  = new DateTime( $token_info['access_token_expire_datetime'] );
				return $current_datetime >= $expire_datetime;
			}

			return true;
		}

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

			$response = wp_remote_post(
				$credentials['accountsUrl'] . '/oauth/v2/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;
			}

			$current_timestamp = time();
			$expires_in        = isset( $response_data['expires_in'] ) ? absint( $response_data['expires_in'] ) : 3600;
			$new_info          = $token_info;
			$new_info['access_token'] = $response_data['access_token'];
			if ( ! empty( $response_data['api_domain'] ) ) {
				$new_info['api_domain'] = untrailingslashit( $response_data['api_domain'] );
			}
			$new_info['access_token_expire_datetime'] = date( 'Y-m-d H:i:s', $current_timestamp + $expires_in );
			$new_info['tokeninfo_updated_datetime']   = current_time( 'mysql' );
			update_option( 'wordform_connect_zohocrm_token', $new_info );

			return $new_info['access_token'];
		}

		public static function get_zohocrm_access_token() {
			$token_info = self::get_zohocrm_token_info();
			if ( ! empty( $token_info['access_token'] ) && ! self::is_zohocrm_access_token_expired() ) {
				return $token_info['access_token'];
			}

			return self::refresh_zohocrm_access_token();
		}

		public static function wordform_connect_create_zohocrm_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_zohocrm_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'       => 'zohocrm-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']  = 'Zoho CRM connected successfully.';
							self::$output['comment'] = 'Zoho CRM connected successfully.';
						} else {
							self::$output['status']  = 'fail';
							self::$output['reason']  = 'Connection info storing failed.';
							self::$output['comment'] = 'Could not create Zoho CRM connection record.';
						}
					} else {
						self::$output['status']  = 'fail';
						self::$output['reason']  = 'Zoho CRM authorization not completed.';
						self::$output['comment'] = 'Please complete Zoho CRM 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_zohocrm( $forms_data = [] ) {
			$send_info                    = [];
			$send_info['applicationSlug'] = 'zohocrm';

			$access_token = self::get_zohocrm_access_token();
			$token_info   = self::get_zohocrm_token_info();
			$api_domain   = isset( $token_info['api_domain'] ) ? untrailingslashit( $token_info['api_domain'] ) : '';
			if ( empty( $access_token ) || empty( $api_domain ) ) {
				$send_info['status']  = 'fail';
				$send_info['reason']  = 'Zoho CRM access token or API domain missing.';
				$send_info['comment'] = 'Zoho CRM 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'] = 'Zoho CRM 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'] ) ) );
			$record = [
				'Email'     => $contact_properties['email'],
				'Last_Name' => $last_name,
			];
			if ( ! empty( $contact_properties['firstName'] ) ) {
				$record['First_Name'] = $contact_properties['firstName'];
			}
			if ( ! empty( $contact_properties['phone'] ) ) {
				$record['Phone'] = $contact_properties['phone'];
			}

			$response = wp_remote_post(
				$api_domain . '/crm/v8/Contacts/upsert',
				[
					'timeout' => 20,
					'headers' => [
						'Authorization' => 'Zoho-oauthtoken ' . $access_token,
						'Content-Type'  => 'application/json; charset=utf-8',
					],
					'body'    => wp_json_encode(
						[
							'data'                  => [ $record ],
							'duplicate_check_fields'=> [ 'Email' ],
						]
					),
				]
			);

			if ( is_wp_error( $response ) ) {
				$send_info['status']       = 'fail';
				$send_info['reason']       = 'Zoho CRM request failed.';
				$send_info['requestError'] = $response->get_error_message();
				$send_info['comment']      = 'Zoho CRM 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 Zoho CRM.';
				$send_info['comment'] = 'Zoho CRM contact synced successfully.';
				if ( is_array( $response_data ) && ! empty( $response_data['data'][0]['details']['id'] ) ) {
					$send_info['recordId'] = sanitize_text_field( $response_data['data'][0]['details']['id'] );
				}
			} else {
				$send_info['status']  = 'fail';
				$send_info['reason']  = 'Zoho CRM response status indicates failure.';
				$send_info['comment'] = 'Zoho CRM 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_zohocrm_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, 'zohocrm', 'active' ] ), ARRAY_A );
			return ! empty( $query_results );
		}
	}
}
