<?php

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

require_once __DIR__ . '/../vendor/autoload.php'; // Carregar SDK
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

class ESLP_GoogleAuthCallback {
	
	private static $eslp_easy_social_login_extra = null;
	
	/**
	 * Class constructor.
	 *
	 * Initializes the class by requiring the necessary file and 
	 * instantiating the ESLP_Easy_Social_Login_Extra class.
	 */
	public function __construct() {	
		require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/eslp-easy-social-login-extra.php';
		
		// Instantiate the ESLP_Easy_Social_Login_Extra class.
		self::$eslp_easy_social_login_extra = new ESLP_Easy_Social_Login_Extra();
	}

	/**
	 * Handles the Google OAuth callback after user authentication.
	 *
	 * This function processes the OAuth response from Google, verifies security parameters,
	 * exchanges the authorization code for an access token, retrieves user information,
	 * and logs the user into WordPress.
	 */
	public function handle_google_oauth_callback() {
		
		// Verify if 'code' and 'state' are present in the URL.
		if (isset($_GET['code']) && isset($_GET['state'])) {
			
			// Sanitize and decode the state parameter.
			$state_raw = wp_unslash( $_GET['state'] ); // Remove slashes.
			$state_raw = sanitize_text_field( $state_raw ); // Sanitize input.
			
			$state = json_decode( $state_raw, true ); // Decode JSON to array.
		
			// Verify the nonce to prevent CSRF attacks.
			if (!wp_verify_nonce($state['nonce'], 'eslp_google_login')) {
				echo esc_html( self::$eslp_easy_social_login_extra->eslp_esc_message(
					__( 'Security check failed. Invalid nonce.', 'easy-social-login' ), 'die'
					)
				);
			}
			
			// Retrieve and sanitize the authorization code.
			$auth_code = wp_unslash( $_GET['code'] ); // Remove slashes.
			$auth_code = sanitize_textarea_field( $auth_code ); // Use a more appropriate sanitizer.

			// Retrieve Google OAuth configuration settings.
			$client_id = get_option( 'eslp_google_client_id' );
			$client_secret = get_option( 'eslp_google_client_secret' );
			$redirect_uri = get_option( 'eslp_google_redirect_uri' );

			try {
				// Exchange the authorization code for an access token.
				$token = self::exchange_code_for_token( $auth_code, $client_id, $client_secret, $redirect_uri );

				// Retrieve user information from Google.
				$user_data = self::get_user_info($token);

				// Authenticate the user in WordPress.
				self::authenticate_user($user_data, $state['redirect_url']);
			} catch (Exception $e) {
				echo esc_html( $eslp_easy_social_login_extra->eslp_esc_message(
					__( 'Error during the login process: ', 'easy-social-login' ) . esc_html( $e->getMessage() ),
					'die'
					)
				);
			}
		} else {
			// Redirect safely if the required parameters are missing.
			wp_safe_redirect( sanitize_url( home_url() ) );
			exit;
		}
	}

	/**
	 * Exchanges an authorization code for an access token from Google OAuth.
	 *
	 * This function sends a request to Google's OAuth 2.0 token endpoint to exchange
	 * the authorization code for an access token.
	 *
	 * @param string $auth_code     The authorization code received from Google.
	 * @param string $client_id     The client ID of the Google OAuth application.
	 * @param string $client_secret The client secret of the Google OAuth application.
	 * @param string $redirect_uri  The redirect URI configured in the OAuth application.
	 *
	 * @return string The access token if the exchange is successful.
	 * @throws Exception If an error occurs during the token exchange process.
	 */
	private function exchange_code_for_token($auth_code, $client_id, $client_secret, $redirect_uri) {
		$client = new Client();

		try {
			$response = $client->post('https://oauth2.googleapis.com/token', [
				'form_params' => [
					'code'          => $auth_code,
					'client_id'     => $client_id,
					'client_secret' => $client_secret,
					'redirect_uri'  => $redirect_uri,
					'grant_type'    => 'authorization_code',
				]
			]);

			$data = json_decode($response->getBody(), true);

			if (isset($data['access_token'])) {
				return $data['access_token'];
			} else {
				throw new Exception(
					esc_html( self::$eslp_easy_social_login_extra->eslp_esc_message(
						__( 'Access token missing from response.', 'easy-social-login' )
						)
					)
				);
			}

		} catch (RequestException $e) {
			$error_message = $e->getResponse() ? $e->getResponse()->getBody()->getContents() : $e->getMessage();
			
			// Log error details for debugging.
			error_log( 'Google OAuth Token Exchange Error: ' . $error_message );

			throw new Exception(
					esc_html( self::$eslp_easy_social_login_extra->eslp_esc_message(
					__( 'Error obtaining access token. Please try again later.', 'easy-social-login' )
					)
				)
			);
		}
	}

	/**
	 * Retrieves user information from Google using an access token.
	 *
	 * This function sends a request to Google's OAuth 2.0 userinfo endpoint to obtain
	 * user details such as email and profile information.
	 *
	 * @param string $access_token The access token obtained from Google OAuth.
	 *
	 * @return array The user data retrieved from Google.
	 * @throws Exception If an error occurs while fetching user information.
	 */
	private function get_user_info($access_token) {
		$client = new Client();

		try {
			 // Send a GET request to Google's userinfo endpoint.	
			$response = $client->get('https://www.googleapis.com/oauth2/v2/userinfo', [
				'headers' => [
					'Authorization' => 'Bearer ' . $access_token,
					'Accept'        => 'application/json'
				]
			]);

			// Check if the request was successful.
			if ( $response->getStatusCode() !== 200 ) {
				throw new Exception( 
					esc_html( self::$eslp_easy_social_login_extra->eslp_esc_message(
						__( 'Unexpected response from Google.', 'easy-social-login' )
						)
					)
				);
			}

			// Decode the JSON response.
			$data = json_decode($response->getBody(), true);

			if (isset($data['email'])) {
				return $data;
			} else {
				throw new Exception(
						esc_html( self::$eslp_easy_social_login_extra->eslp_esc_message(
						__( 'User details not found.', 'easy-social-login' )
						)
					)
				);
			}

		} catch (RequestException $e) {
			$error_message = $e->getResponse() ? $e->getResponse()->getBody()->getContents() : esc_html( $e->getMessage() );
			
			// Log error details for debugging.
			error_log( 'Google OAuth User Info Error: ' . $error_message );
		
			throw new Exception(
					esc_html( self::$eslp_easy_social_login_extra->eslp_esc_message(
					__( 'Error retrieving user information. Please try again later.', 'easy-social-login' )
					)
				)
			);
		}
	}

	/**
	 * Authenticates or registers a user using Google OAuth data.
	 *
	 * This function checks if a user exists based on their Google email. If the user does not exist,
	 * a new WordPress user account is created. The user is then logged in and redirected
	 * to the specified URL.
	 *
	 * @param array  $user_data    The user data retrieved from Google OAuth.
	 * @param string $redirect_url The URL to redirect the user after authentication.
	 */
	private function authenticate_user($user_data, $redirect_url) {
		$email = sanitize_email( $user_data['email'] );
		$google_id = sanitize_text_field( $user_data['id'] );
		$user = get_user_by('email', $email);

		// If user does not exist, create a new account
		if (!$user) {
			$user_id = wp_create_user($email, wp_generate_password(), $email);
			$role = get_option('eslp_easy_social_login_user_role', 'subscriber');
			wp_update_user([
				'ID'         => $user_id,
				'display_name' => sanitize_text_field(  $user_data['given_name'] ) ?? sanitize_text_field(  $user_data['name'] ),
				'nickname' => sanitize_text_field( $user_data['given_name'] ) ?? sanitize_text_field( $user_data['name'] ),
				'first_name' => sanitize_text_field(  $user_data['given_name'] ) ?? '',
				'last_name'  => sanitize_text_field(  $user_data['family_name'] ) ?? '',
				'role' => $role,
			]);
			
			// Add the Google ID as user meta for future reference
			update_user_meta( $user_id, 'eslp_google_id', $google_id );

			// Store Google ID as user meta
			$user = get_user_by('id', $user_id);
			
			// Notify admin if the option is enabled
			if ('not-exists' !== get_option('eslp_easy_social_login_notify_admin', 'not-exists')) {
				if (get_option('eslp_easy_social_login_notify_admin') == true) {
					wp_new_user_notification($user->ID, null, 'admin');
				}
			}
		}

		// Ensure valid redirection URL
		add_filter('allowed_redirect_hosts', function ($hosts) use ($redirect_url) {
			$parsed_url = wp_parse_url($redirect_url);
			if (isset($parsed_url['host'])) {
				$hosts[] = $parsed_url['host'];
			}
			return $hosts;
		});
		wp_set_auth_cookie($user->ID, true);
		wp_safe_redirect( sanitize_url( $redirect_url ) );
		exit;
	}
}
$google_auth_callback = new ESLP_GoogleAuthCallback();
$google_auth_callback->handle_google_oauth_callback();