<?php
/**
 * Prohibit direct script loading
 */
defined('ABSPATH') || die('No direct script access allowed!');

/**
 * Class Wpms_Api_Google_Client
 */
class Wpms_Api_Google_Client extends Wpms_Google_Client
{
    protected $option_refresh_token;
    protected $option_access_token;
    protected $api_url;
    protected $http_response_code;

    /**
     * Init config and refresh token
     */
    public function __construct($config, $option_prefix, $api_url = '')
    {

        parent::__construct();

        $this->option_refresh_token = $option_prefix . '-refresh_token';
        $this->option_access_token  = $option_prefix . '-access_token';
        $this->api_url              = $api_url;
        $this->init_config($config);
        $this->refresh_tokens();
    }

    /**
     * Authenticate the client
     */
    public function authenticate_client($authorization_code = null)
    {
        static $has_retried;

        // Authenticate client.
        try {
            $this->authenticate($authorization_code);

            // Get access response.
            $response = $this->getAccessToken();

            // Check empty response
            if (!empty($response)) {
                $response = json_decode($response);

                if (is_object($response)) {
                    // Save refresh token.
                    $this->save_refresh_token($response->refresh_token);

                    return true;
                }
            }
        } catch (Wpms_Google_AuthException $exception) {
            if (empty($has_retried)) {
                $has_retried = true;

                return $this->authenticate_client($authorization_code);
            }
        }

        return false;
    }

    /**
     * Doing a request to the API
     */
    public function do_request($target_request_url, $decode_response = false, $request_method = 'GET')
    {
        // Get response.
        $response = $this->getIo()->authenticatedRequest(
            new Wpms_Google_HttpRequest($this->api_url . $target_request_url, $request_method)
        );

        // Storing the response code.
        $this->http_response_code = $response->getResponseHttpCode();

        if ($decode_response) {
            return $this->decode_response($response);
        }

        return $response;
    }

    /**
     * Decode response
     */
    public function decode_response($response, $accepted_response_code = 200)
    {
        if ($accepted_response_code === $response->getResponseHttpCode()) {
            return json_decode($response->getResponseBody());
        }
    }

    /**
     * Get the response code
     */
    public function get_http_response_code()
    {
        return $this->http_response_code;
    }

    /**
     * Clears option
     */
    public function clearData()
    {
        $this->revokeToken();

        delete_option($this->option_access_token);
        delete_option($this->option_refresh_token);
    }

    /**
     * Check if user is authenticated
     */
    public function is_authenticated()
    {
        $has_refresh_token    = ($this->get_refresh_token() !== '');
        $access_token_expired = $this->access_token_expired();

        return $has_refresh_token && !$access_token_expired;
    }

    /**
     * Init config
     */
    protected function init_config(array $config)
    {
        if (!empty($config['application_name'])) {
            $this->setApplicationName($config['application_name']);
        }

        if (!empty($config['client_id'])) {
            $this->setClientId($config['client_id']);
        }

        if (!empty($config['client_secret'])) {
            $this->setClientSecret($config['client_secret']);
        }

        // Set our settings.
        $this->setRedirectUri($config['redirect_uri']);
        $this->setScopes($config['scopes']);
        $this->setAccessType('offline');
    }

    /**
     * Refresh token
     */
    protected function refresh_tokens()
    {
        if (($refresh_token = $this->get_refresh_token()) !== '' && $this->access_token_expired()) {
            try {
                // Refresh the token.
                $this->refreshToken($refresh_token);

                $response = $this->getAuth()->token;

                // Check response and if there is an access_token.
                if (!empty($response) && !empty ($response['access_token'])) {
                    $this->save_access_token($response);
                }
            } catch (Exception $e) {
                return false;
            }
        }
    }

    /**
     * Save refresh token
     */
    protected function save_refresh_token($refresh_token)
    {
        update_option($this->option_refresh_token, trim($refresh_token));
    }

    /**
     * Return refresh token
     */
    protected function get_refresh_token()
    {
        return get_option($this->option_refresh_token, '');
    }

    /**
     * Save the access token
     */
    protected function save_access_token($response)
    {
        update_option(
            $this->option_access_token,
            array(
                'refresh_token' => $this->get_refresh_token(),
                'access_token'  => $response['access_token'],
                'expires'       => current_time('timestamp') + $response['expires_in'],
                'expires_in'    => $response['expires_in'],
                'created'       => $response['created'],
            )
        );

        $this->setAccessToken(json_encode($response));
    }

    /**
     * Check if current access token is expired.
     */
    private function access_token_expired()
    {
        $access_token = $this->get_access_token();

        if (current_time('timestamp') >= $access_token['expires']) {
            return true;
        }

        $this->setAccessToken(json_encode($access_token));
    }

    /**
     * Getcurrent access token
     */
    private function get_access_token()
    {
        return get_option($this->option_access_token, array('access_token' => false, 'expires' => 0));
    }
}
