<?php
/**
 * DESCRIPTION: Handles Google OAuth 2.0 authorization flow for Google Calendar integration.
 * Stores and retrieves OAuth tokens in wp_options keyed per option name.
 *
 * @package NemtlyBooking\Integrations\Google
 */

namespace NemtlyBooking\Integrations\Google;

use Google\Client;

/**
 * Google OAuth Provider
 *
 * Manages the OAuth 2.0 authorization flow used to connect
 * the site to a Google account for Calendar sync.
 *
 * @since PBOOKING_SINCE
 */
class Google_OAuth_Provider {

    /**
     * WordPress options key for storing the OAuth access token.
     */
    const TOKEN_OPTION = 'nemtly_google_oauth_token';

    /**
     * WordPress options key for storing the Google Calendar ID to sync with.
     */
    const CALENDAR_ID_OPTION = 'nemtly_google_calendar_id';

    /**
     * Build and return a configured Google API client.
     *
     * @since PBOOKING_SINCE
     *
     * @return Client|null Configured client, or null if credentials are not set.
     */
    public function get_client() {
        $settings = get_option( 'nemtly_booking_settings', [] );

        $client_id     = ! empty( $settings['google_client_id'] ) ? $settings['google_client_id'] : '';
        $client_secret = ! empty( $settings['google_client_secret'] ) ? $settings['google_client_secret'] : '';

        if ( empty( $client_id ) || empty( $client_secret ) ) {
            return null;
        }

        $client = new Client();
        $client->setClientId( $client_id );
        $client->setClientSecret( $client_secret );
        $client->setRedirectUri( $this->get_redirect_uri() );
        $client->addScope( \Google\Service\Calendar::CALENDAR );
        $client->setAccessType( 'offline' );
        $client->setPrompt( 'consent' );

        $token = get_option( self::TOKEN_OPTION );
        if ( $token ) {
            $client->setAccessToken( $token );

            // Refresh the token automatically if it has expired.
            if ( $client->isAccessTokenExpired() && $client->getRefreshToken() ) {
                $refreshed = $client->fetchAccessTokenWithRefreshToken( $client->getRefreshToken() );
                if ( ! isset( $refreshed['error'] ) ) {
                    update_option( self::TOKEN_OPTION, $client->getAccessToken() );
                }
            }
        }

        return $client;
    }

    /**
     * Generate the OAuth authorization URL to redirect the admin to.
     *
     * @since PBOOKING_SINCE
     *
     * @return string|null Authorization URL, or null if credentials are missing.
     */
    public function get_authorization_url() {
        $client = $this->get_client();

        if ( ! $client ) {
            return null;
        }

        return $client->createAuthUrl();
    }

    /**
     * Exchange an authorization code for an access token and store it.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $code Authorization code from Google.
     *
     * @return bool True on success, false on failure.
     */
    public function exchange_code_for_token( $code ) {
        $client = $this->get_client();

        if ( ! $client ) {
            return false;
        }

        $token = $client->fetchAccessTokenWithAuthCode( $code );

        if ( isset( $token['error'] ) ) {
            return false;
        }

        update_option( self::TOKEN_OPTION, $token );

        return true;
    }

    /**
     * Check whether valid (non-expired, refreshable) credentials are stored.
     *
     * @since PBOOKING_SINCE
     *
     * @return bool
     */
    public function is_connected() {
        $client = $this->get_client();

        if ( ! $client ) {
            return false;
        }

        $token = get_option( self::TOKEN_OPTION );
        if ( ! $token ) {
            return false;
        }

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

        // Still connected if we have a refresh token.
        return ! empty( $client->getRefreshToken() );
    }

    /**
     * Revoke and delete the stored OAuth token.
     *
     * @since PBOOKING_SINCE
     *
     * @return void
     */
    public function disconnect() {
        $client = $this->get_client();

        if ( $client ) {
            $token = get_option( self::TOKEN_OPTION );
            if ( $token ) {
                $client->revokeToken( $token );
            }
        }

        delete_option( self::TOKEN_OPTION );
    }

    /**
     * Return the OAuth callback URL that must be registered in Google Cloud Console.
     *
     * @since PBOOKING_SINCE
     *
     * @return string
     */
    public function get_redirect_uri() {
        return rest_url( 'nemtly-booking/v1/google-auth/callback' );
    }
}
