<?php

namespace IGD;

defined( 'ABSPATH' ) || exit();

class Client {

	/**
	 * Client instances per account.
	 *
	 * @var array
	 */
	private static $instance = null;

	/**
	 * Google client instance.
	 *
	 * @var \IGDGoogle_Client|null
	 */
	public $client = null;

	private $client_id;
	private $client_secret;
	private $redirect_uri;

	public $account_id;
	public $account = [];

	/**
	 * Constructor.
	 *
	 * @param string|null $account_id
	 */
	public function __construct( $account_id = null ) {

		if ( ! class_exists( 'IGDGoogle_Client' ) ) {
			require_once IGD_PATH . '/vendors/Google-sdk/src/Google/autoload.php';
		}

		$this->init_account( $account_id );
		$this->init_credentials();
	}

	/**
	 * Initialize account data.
	 *
	 * @param string|null $account_id
	 */
	private function init_account( $account_id ) {

		$account = empty( $account_id )
			? Account::instance()->get_active_account()
			: Account::instance()->get_accounts( $account_id );

		$this->account_id = ! empty( $account['id'] )
			? sanitize_text_field( $account['id'] )
			: $account_id;

		$this->account = is_array( $account ) ? $account : [];
	}

	/**
	 * Initialize OAuth credentials.
	 */
	private function init_credentials() {

		$this->client_id = sanitize_text_field(
			apply_filters( 'igd/client_id', '885430345856-7dfh13l81oql8d8toae6ecs0865jbmsh.apps.googleusercontent.com' )
		);

		$this->client_secret = sanitize_text_field(
			apply_filters( 'igd/client_secret', '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' )
		);

		$this->redirect_uri = esc_url_raw(
			apply_filters( 'igd/redirect_uri', 'https://softlabbd.com/integrate-google-drive-oauth.php' )
		);
	}

	/**
	 * Get initialized Google client.
	 *
	 * @return \IGDGoogle_Client|\Exception
	 */
	public function get_client() {

		if ( $this->client instanceof \IGDGoogle_Client ) {
			return $this->client;
		}

		return $this->client = $this->start_client();
	}

	/**
	 * Bootstrap Google client.
	 *
	 * @return \IGDGoogle_Client|\Exception
	 */
	private function start_client() {

		try {
			$this->client = new \IGDGoogle_Client();
		} catch ( \Exception $e ) {

			error_log(
				sprintf(
					'[Integrate Google Drive] Failed to initialize Google Client: %s',
					sanitize_text_field( $e->getMessage() )
				)
			);

			return $e;
		}

		$this->client->setApplicationName( 'Integrate Google Drive - ' . sanitize_text_field( IGD_VERSION ) );
		$this->client->setClientId( $this->client_id );
		$this->client->setClientSecret( $this->client_secret );
		$this->client->setRedirectUri( $this->redirect_uri );
		$this->client->setAccessType( 'offline' );
		$this->client->setApprovalPrompt( 'force' );

		$this->set_scopes();
		$this->set_state();

		if ( empty( $this->account ) ) {
			return $this->client;
		}

		$authorization = new Authorization( $this->account_id );

		if ( ! $authorization->has_access_token() ) {
			return $this->client;
		}

		$access_token = $authorization->get_access_token();

		if ( empty( $access_token ) ) {
			return $this->client;
		}

		$this->client->setAccessToken( $access_token );

		if ( ! $this->client->isAccessTokenExpired() ) {
			return $this->client;
		}

		// If we end up here, we have to refresh the token
		return $authorization->refresh_token( $this->account );

	}

	/**
	 * Set OAuth state.
	 *
	 * @param \IGDGoogle_Client $client
	 */
	private function set_state() {
		$state = apply_filters( 'igd_auth_state', admin_url( 'admin.php?page=integrate-google-drive&action=authorization' ) );

		$this->client->setState( base64_encode( sanitize_url( $state ) ) );
	}

	/**
	 * Set Google API scopes.
	 *
	 * @param \IGDGoogle_Client $client
	 */
	public function set_scopes() {

		$scope_key = ! empty( $this->account['scope'] ) ? $this->account['scope'] : 'entire_drive';
		$scopes    = igd_get_scopes_by_access_level( $scope_key );

		$this->client->setScopes( $scopes );
	}

	/**
	 * Get Google auth URL.
	 *
	 * @return string
	 */
	public function get_auth_url() {
		return $this->get_client()->createAuthUrl();
	}

	/**
	 * Handle OAuth callback and store token.
	 *
	 * @return true|\WP_Error
	 */
	public function create_access_token() {

		if ( empty( $_GET['code'] ) ) {
			return new \WP_Error( 'missing_code', __( 'Authorization code is missing.', 'integrate-google-drive' ) );
		}

		if ( empty( $_GET['state'] ) ) {
			return new \WP_Error( 'missing_state', __( 'State parameter is missing.', 'integrate-google-drive' ) );
		}

		try {
			$code  = sanitize_text_field( wp_unslash( $_GET['code'] ) );
			$state = esc_url_raw( base64_decode( sanitize_text_field( wp_unslash( $_GET['state'] ) ), true ) );

			if ( ! $state ) {
				return new \WP_Error( 'invalid_state', __( 'Invalid state parameter.', 'integrate-google-drive' ) );
			}

			$token = $this->get_client()->authenticate( $code );

			$service = App::instance( $this->account_id )->getService();
			$about   = $service->about->get( [ 'fields' => 'user,storageQuota' ] );

			$data = [
				'id'      => sanitize_text_field( $about->getUser()->getPermissionId() ?? '' ),
				'name'    => sanitize_text_field( $about->getUser()->getDisplayName() ?? '' ),
				'email'   => sanitize_email( $about->getUser()->getEmailAddress() ?? '' ),
				'photo'   => esc_url_raw( $about->getUser()->getPhotoLink() ?? '' ),
				'storage' => [
					'usage' => $about->getStorageQuota()->getUsage() ?? 0,
					'limit' => $about->getStorageQuota()->getLimit() ?? 0,
				],
				'lost'    => false,
			];

			// Store authorization
			( new Authorization( $data['id'] ) )->set_access_token( $token );

			// Extract state parameters
			$state_args = [];
			parse_str( wp_parse_url( $state, PHP_URL_QUERY ), $state_args );

			// Determine user ID, Default to 'admin' if not provided
			$user_id         = ! empty( $state_args['user_id'] ) ? (int) $state_args['user_id'] : 'admin';
			$data['user_id'] = [ $user_id ];

			// Set scope key
			$data['scope'] = ! empty( $state_args['scope'] ) ? $state_args['scope'] : 'entire_drive';

			// Add root folder ID only for 'entire_drive' scope
			if ( 'entire_drive' == $data['scope'] ) {
				$data['root_id'] = sanitize_text_field( $service->files->get( 'root', [ 'fields' => 'id' ] )->getId() ?? '' );
			}

			// Update or create account
			$data = Account::instance( $user_id )->update_account( $data );
			Account::instance( $user_id )->set_active_account_id( $data['id'] );

			// Create App Folder if needed
			if ( 'app_folder' === $data['scope'] ) {
				$app_folder = App::instance( $data['id'] )->get_app_folder();

				// Store App Folder ID
				if ( ! empty( $app_folder ) ) {
					$data['app_folder'] = $app_folder;
					$data['root_id']    = sanitize_text_field( $app_folder['id'] );

					// Save the updated account with app_folder_id
					Account::instance( $user_id )->update_account( $data );
				}

			}

			$timestamp = wp_next_scheduled( 'igd_lost_authorization_notice', [ 'account_id' => $data['id'] ] );
			if ( $timestamp ) {
				wp_unschedule_event( $timestamp, 'igd_lost_authorization_notice', [ 'account_id' => $data['id'] ] );
			}

			return $data;

		} catch ( \Exception $e ) {

			error_log(
				sprintf(
					'[Integrate Google Drive] OAuth error: %s',
					sanitize_text_field( $e->getMessage() )
				)
			);

			return new \WP_Error( 'token_error', __( 'Error communicating with Google API.', 'integrate-google-drive' ) );
		}
	}

	/**
	 * Get client instance per account.
	 *
	 * @param string|null $account_id
	 *
	 * @return self
	 */
	public static function instance( $account_id = null ) {

		if ( is_null( self::$instance ) || self::$instance->account_id != $account_id ) {
			self::$instance = new self( $account_id );
		}

		return self::$instance;
	}
}