<?php
/**
 * Interactions with Google API - PHP SDK
 * NOTE: Designed to be used with PHP v8.0.2 and up
 * 
 * @author Luca Montanari
 */
 
if (version_compare(PHP_VERSION, '8.0.2', '<')) {
  throw new Exception('Google SDK requires PHP version 8.0.2 or higher');
} 
 
 
class gg_gdrive_integration {
	private $client; // (object) client object set up by google class
	private $service;  // (object) gDrive service object set up by google class
	
	public $main_folder_id; // (string) contains "globalgallery" wrapper folder in googledrive account
	public $g_username; // (string) 
	
    
    
	/* get google username from connection ID - or set it manually */
	public function __construct($connect_id, $username = false) {
		if(!function_exists('google_api_php_client_autoload')) {
			include_once(GG_DIR .'/classes/google-api-php-client-2.18.2/vendor/autoload.php');
		}
        include_once(GG_DIR .'/classes/gg_connections_hub.php');
        
        if(empty($connect_id)) {
			$this->g_username = $username;	
		} 
		else {
			$conn_data = gg_connection_hub::get_data(false, $connect_id);
			$this->g_username = (!is_array($conn_data) || !isset($conn_data['gdrive_user'])) ? false : $conn_data['gdrive_user'];
		}
        
        
        $client = new Google_Client();
        $client->setApplicationName('Global Gallery');
        $client->setDeveloperKey("AIzaSyAWlMPGJpioHtvgBk3WprG2nj1mGZPsBzA");
        
        $client->setScopes(Google_Service_Drive::DRIVE_METADATA_READONLY);
        $client->setAuthConfig(GG_DIR .'/classes/google-api-php-client-2.18.2/gg_app_credentials.json');
        $client->setAccessType('offline');
        $client->setPrompt('select_account consent');
        
        $this->client = $client;
	}
	
	
    
    
	/* first check - let user accept the app and get refresh token */
	public function accept_app() {
        return $this->client->createAuthUrl();
	}

    
    

    /* get access and refresh token - to perform only in connection setup 
	 * @param (string) $base_token - initial token submitted by user
	 */
    public function get_access_token($base_token) {
        try {
            $base_token = urldecode($base_token);
            $base_tokens_arr = explode('&', $base_token);
            $base_token = $base_tokens_arr[0]; 
            
			$accessToken = $this->client->fetchAccessTokenWithAuthCode($base_token);
            $this->client->setAccessToken($accessToken);

            // Check to see if there was an error.
            if(array_key_exists('error', $accessToken)) {
                throw new Exception(join(', ', $accessToken));
            }
		}
		catch(Exception $e) {
			//var_dump($e); // debug
			return false;
		}
		
		if(is_array($accessToken) && isset($accessToken['refresh_token'])) {
			// store 
			$this->base_tokens_db('set', array('base' => $base_token, 'refresh' => $accessToken['refresh_token'])); 
			return $accessToken['refresh_token'];
		} 
		else {
			//var_dump($accessToken); // debug
			return false;	
		}
	}
    
    
    
    
    
    /* manage base tokens database to avoid expired tokens
	 * 
	 *  @param string $action - action to perform - set/get
	 *  @param array $tokens - associative array of base token + refresh token
	 */
	public function base_tokens_db($action, $tokens = array('base' => '', 'refresh' => '')) {
		$db = (array)get_option('gg_gdrive_base_tokens_db', array());
		$username = $this->g_username;
		
		// set
		if($action == 'set') {
			$db[$username] = $tokens;
			update_option('gg_gdrive_base_tokens_db', $db);
		}
		
		// get
		else {
			return (isset($db[$username])) ? $db[$username] : false; 	
		}
	}
    
    
    
	
	/* 
	 * check if is possible to perform a request and setup service property
	 */
	private function is_ok() {
        if(!$this->g_username) {
            return false;    
        }
        
        try {
            $stored = get_option('gg_gdrive_base_tokens_db', array());
            $stored_keys = $stored[ $this->g_username ];
            
            $this->client->fetchAccessTokenWithRefreshToken($stored_keys['refresh']);
            $this->service = new Google_Service_Drive( $this->client );
        } 
        catch (Exception $e) {
            return false;
        }
		return true;
	}
	
    	
	
	
	
	//////////////////////////////////////////////////////////////////////////////////////////////////
	

    
    
    
	/* GET WRAPPER "globalgallery" FOLDER ID */
	public function set_wrap_folder_id() {
		if(!$this->is_ok()) {
            return false;
        }
        $optParams = array(
            'pageSize' => 1000,
            'q' => "mimeType = 'application/vnd.google-apps.folder' and 'root' in parents and trashed=false"
        );
        $results = $this->service->files->listFiles($optParams);
        $items = $results->getFiles();
        
        
        if(!is_array($items)) {
            $this->main_folder_id = false;
            return false;
        }

        foreach($items as $file) {
            if($file->getName() == 'globalgallery') {
                $this->main_folder_id = $file->getId();
                break;	
            }
        }

        return $this->main_folder_id;
	}
		


	
	/* LIST FOLDERS containing galleries
	 * @return (mixed) 
	 	false if connection failed
		albums array (could be empty)
	 */
	public function list_albums() {
		if(!$this->is_ok()) {
            return false;    
        }
        if(!$this->set_wrap_folder_id()) {
            return esc_html__('Main folder missing. A public "globalgallery" folder is needed in your Drive root.', 'gg_ml');	
        }
        
        $optParams = array(
            'pageSize' => 1000,
            'q' => "mimeType = 'application/vnd.google-apps.folder' and '". $this->main_folder_id ."' in parents and trashed=false"
        );
        $results = $this->service->files->listFiles($optParams);
        $items = $results->getFiles();

        if(!is_array($items)) {
            return esc_html__('Error querying albums', 'gg_ml');
        }
        if(!count($items)) {
            return esc_html__('No albums found', 'gg_ml');
        }

        $folders = array();
        foreach($results->getFiles() as $file) {
            $folders[ $file->getId() ] = $file->getName();
        }

        return $folders;
	}
	
	
    
    
    
	/* GET IMAGES 
	 * @return (mixed) 
	 	false if connection failed
		albums array (could be empty)
	 */
	public function get_images($folder_id, $search = false) {
		if(!$this->is_ok()) {
            return false;
        } 
        if(!$this->set_wrap_folder_id()) {
            return esc_html__('Main folder missing', 'gg_ml');	
        }

        $search_part = (empty($search)) ? '' : "and fullText contains '". str_replace("'", "\'", $search) ."'";

        $optParams = array(
            'pageSize'=> 999,
            'orderBy'	=> (empty($search)) ? 'name' : '', // Google doesn't allow sorting on search
            'q'			=> "'". $folder_id ."' in parents and trashed = false and (mimeType = 'image/jpeg' or mimeType = 'image/png' or mimeType = 'image/gif' or mimeType = 'image/webp' or mimeType = 'image/avif') ". $search_part, 
            'fields'	=> 'files(description,owners/displayName,name,webContentLink)'
        );
        $results = $this->service->files->listFiles($optParams);

        $images = array();
        foreach($results->getFiles() as $file) {
            $images[] = array(
                'url' 	=> str_replace('&export=download', '', $file->webContentLink), 
                'author'=> $file->owners[0]->displayName,
                'title'	=> (string)$file->name,
                'descr'	=> (string)$file->description
            );
        }

        return $images;
	}

    
}
