<?php

namespace Limb_Chatbot\Includes\AI_Providers\Gemini\Services;

use Limb_Chatbot\Includes\Data_Objects\Setting;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;

/**
 * Class Google_OAuth_Service
 *
 * Handles Google OAuth token retrieval and refresh for API authentication.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Gemini\Services
 * @since 1.0.0
 */
class Google_OAuth_Service {

	/**
	 * Setting key for OAuth token expiry timestamp.
	 */
	const SETTING_EXPIRES_IN = 'lbaic.settings.google.oauth.expires_in';

	/**
	 * Setting key for OAuth access token.
	 */
	const SETTING_ACCESS_TOKEN = 'lbaic.settings.google.oauth.access_token';

	/**
	 * Setting key for OAuth client ID.
	 */
	const SETTING_CLIENT_ID = 'lbaic.settings.google.oauth.client_id';

	/**
	 * Setting key for OAuth client secret.
	 */
	const SETTING_CLIENT_SECRET = 'lbaic.settings.google.oauth.client_secret';

	/**
	 * Setting key for OAuth refresh token.
	 */
	const SETTING_REFRESH_TOKEN = 'lbaic.settings.google.oauth.refresh_token';

	/**
	 * URL for Google's OAuth2 token endpoint.
	 */
	const TOKEN_URL = "https://oauth2.googleapis.com/token";

	/**
	 * Retrieves a valid OAuth access token, refreshing it if expired.
	 *
	 * @return string OAuth access token.
	 * @throws Exception Throws if unauthorized or refresh fails.
	 * @since 1.0.0
	 */
	public function get_oauth_token() {
		$expires_at = Setting::find( self::SETTING_EXPIRES_IN )->get_value();
		if ( empty( $expires_at ) ) {
			throw new Exception( Error_Codes::AUTHENTICATION_UNAUTHORIZED, __( 'Unauthorized', 'limb-chatbot' ) );
		}
		if ( $expires_at < time() ) {
			$this->refresh_oauth_token();
		}

		return Setting::find( self::SETTING_ACCESS_TOKEN )->get_value();
	}

	/**
	 * Refreshes the OAuth access token using the refresh token.
	 *
	 * @return void
	 * @throws Exception Throws on technical errors or unexpected response.
	 * @since 1.0.0
	 */
	private function refresh_oauth_token() {
		$refresh_token = Setting::find( self::SETTING_REFRESH_TOKEN )->get_value();
		$client_id     = Setting::find( self::SETTING_CLIENT_ID )->get_value();
		$client_secret = Setting::find( self::SETTING_CLIENT_SECRET )->get_value();
		$body          = array(
			'refresh_token' => $refresh_token,
			'client_id'     => $client_id,
			'client_secret' => $client_secret,
			'grant_type'    => 'refresh_token'
		);
		$response      = wp_remote_post( self::TOKEN_URL, array(
			'body'    => http_build_query( $body ),
			'headers' => array(
				'Content-Type' => 'application/x-www-form-urlencoded'
			)
		) );
		$response      = wp_remote_retrieve_body( $response );
		if ( empty( $response ) ) {
			throw new Exception( Error_Codes::TECHNICAL_ERROR, __( 'Technical error', 'limb-chatbot' ) );
		}
		$response = json_decode( $response );
		if ( empty( $response->access_token ) || empty( $response->expires_in ) ) {
			throw new Exception( Error_Codes::UNEXPECTED_RESPONSE_FORMAT, __( 'Unexpected response format', 'limb-chatbot' ) );
		}
		Setting::update( [ 'key' => self::SETTING_ACCESS_TOKEN ], [ 'value' => $response->access_token ] );
		Setting::update( [ 'key' => self::SETTING_EXPIRES_IN ], [ 'value' => time() + $response->expires_in ] );
	}
}