<?php

/**
 * Classe per la gestione di Google Drive
 * 
 * Passo 1: Creazione del Progetto su Google Cloud Console
 *      Va su Google Cloud Console. (https://console.cloud.google.com/)
 * 
 *      Crea un progetto:
 *          Clicca su "Seleziona un progetto" (in alto a sinistra).
 *          Clicca su "Nuovo progetto", inserisci un nome e conferma la creazione.
 * 
 * Passo 2: Abilitare l'API di Google Drive
 *      Nel menu laterale, vai su "API e Servizi" > "Libreria".
 *      Cerca "Google Drive API".
 *      Clicca su "Abilita" per attivare l'API nel tuo progetto.
 * 
 * Passo 3: Creare le Credenziali OAuth 2.0
 *      Vai su "API e Servizi" > "Credenziali".
 *      Clicca su "Crea credenziali" e seleziona "ID client OAuth".
 * 
 *      Se richiesto, configura la schermata di consenso OAuth:
 *          Inserisci le informazioni richieste (nome dell'app, email di supporto, redirect url, utenti ecc.).
 * 
 *      Nella sezione Ambiti, aggiungi l'ambito:
 *          https://www.googleapis.com/auth/drive.file
 *          Questo ambito consente all'app di leggere e scrivere solo i file creati o caricati dalla tua applicazione.
 * 
 *      Dopo aver configurato la schermata di consenso, crea le credenziali:
 *          Tipo di applicazione: "App per desktop" (o "Web" se usi un'app con redirect URI).
 *      Salva il Client ID e il Client Secret.
 *  
 * Passo 4: Ottenere il Token di Accesso (Access Token)
 *      Nella console di Google Cloud srivere:
 *          curl --location --request POST 'https://oauth2.googleapis.com/token' \
 *          --header 'Content-Type: application/x-www-form-urlencoded' \
 *          --data-urlencode 'client_id=YOUR_CLIENT_ID' \
 *          --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
 *          --data-urlencode 'redirect_uri=YOUR_REFRESH_TOKEN' \
 *          --data-urlencode 'grant_type=authorization_code'
 * 
 *      La risposta conterrà il token di accesso (access_token) e, se richiesto offline, anche un refresh token (refresh_token).
 *  
 * Passo 5: Copiare il token di accesso e il refresh token e salvarli
 * 
*/


namespace RinnovoBooking\Core;

use RinnovoBooking\Core\Notification;

class GoogleDriveHandler
{
    private string $accessToken;
    private $expiresAt;
    private string $refreshToken;
    private string $clientId;
    private string $clientSecret;


    public function __construct()
    {
        global $wpdb;

        //prende i dati del cloud
        $table_name = $wpdb->prefix . RINNOVOBOOKINGPREFIX;
        $mio_cloud = $wpdb->get_results("SELECT `op_val` FROM $table_name WHERE `operazione`= 'cloud'");  
        $cloudSettings = json_decode($mio_cloud['0']->op_val);

        $this->refreshToken = $cloudSettings->refresh_token;
        $this->clientId = $cloudSettings->client_id;
        $this->clientSecret = $cloudSettings->client_secret;

        $response = $this->getAccessToken();

        $mio_token = $wpdb->get_results("SELECT `op_val` FROM $table_name WHERE `operazione`= 'token'");
        $tokenSettings = json_decode($mio_token['0']->op_val);
        $this->accessToken = $tokenSettings->access_token;
        $this->expiresAt = $tokenSettings->expires_at;
    }



    /**
     * Restituisce il token di accesso valido
     * @return string
     */
    public function getAccessToken() {
        if ($this->isTokenExpired()) {
            $token = $this->regenerateAccessToken();
            if($token) {
                $this->saveToken();
            }
        }
        return true;
    }

    
    /**
     * Verifica se il token è scaduto
     * @return bool
     */
    private function isTokenExpired() {
        //prendi il valore dal database
        global $wpdb;
        $table_name = $wpdb->prefix . RINNOVOBOOKINGPREFIX;
        $mio_token = $wpdb->get_results("SELECT `op_val` FROM $table_name WHERE `operazione`= 'token'");  
        if (!$mio_token) {
            return true;
        }

        $token = json_decode($mio_token['0']->op_val);
        return time() >= $token->expires_at;
    }


    /**
     * Salva il token di accesso
     * @return bool
     */
    private function saveToken() {
        global $wpdb;
        $table_name = $wpdb->prefix . RINNOVOBOOKINGPREFIX;

        $existingToken = $wpdb->get_row("SELECT * FROM $table_name WHERE `operazione`= 'token'");
        if (!$existingToken) {
            $wpdb->insert($table_name, array(
                'operazione' => 'token',
                'op_val' => json_encode(array('access_token' => $this->accessToken, 'expires_at' => $this->expiresAt))
            ));
        } else {
            $wpdb->update($table_name, array(
                'op_val' => json_encode(array('access_token' => $this->accessToken, 'expires_at' => $this->expiresAt))
            ), array('operazione' => 'token'));
        }

        if (!$wpdb->insert_id) {
            Notification::display_notification('Errore durante il salvataggio del token: ' . $wpdb->last_error, 'error', 'Errore');
            return false;
        }

        return true;
    }


    /**
     * Rigenera il token di accesso
     * @return string
     */
    private function regenerateAccessToken() {
        // Endpoint di Google OAuth per ottenere il token
        $url = 'https://oauth2.googleapis.com/token';

        // Parametri per la richiesta
        $postData = [
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,
            'refresh_token' => $this->refreshToken,
            'grant_type' => 'refresh_token'
        ];

        // Configurazione della richiesta cURL
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/x-www-form-urlencoded'
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        // Esecuzione della richiesta
        $response = curl_exec($ch);

        // Gestione errori cURL
        if (curl_errno($ch)) {
            Notification::display_notification('Errore cURL: ' . curl_error($ch), 'error', 'Errore');
            return false;
        }

        // Chiusura cURL
        curl_close($ch);
        if (curl_errno($ch)) {
            Notification::display_notification('Errore cURL: ' . curl_error($ch), 'error', 'Errore');
            return false;
        }

        // Decodifica della risposta
        $responseData = json_decode($response, true);

        // Controllo della risposta
        if (isset($responseData['error'])) {
            Notification::display_notification('Errore Google OAuth: ' . $responseData['error_description'], 'error', 'Errore');
            return false;
        }

        // Aggiornamento del token e della scadenza
        $this->accessToken = $responseData['access_token'];
        $this->expiresAt = time() + $responseData['expires_in'];

        return true;
    }




    public function uploadFile(string $filePath, string $fileName, string $dateFolderName, string $subFolderName, string $subFolderSede, string $folderId = 'RinnovoBooking', string $mimeType = 'image/jpeg')
    {
        // Verifica se il file esiste
        if (!file_exists($filePath)) {
            Notification::display_notification("File non trovato: $filePath", 'error', 'Errore');
            return false;
        }
    
        // Ottieni il contenuto del file
        $fileContent = file_get_contents($filePath);
    
        // Crea o ottieni la cartella principale "RinnovoBooking"
        $mainFolderId = $this->getOrCreateFolder(null, $folderId);
        
        // Crea o ottieni la cartella della sede
        $sedeFolderId = $this->getOrCreateFolder($mainFolderId, $subFolderSede);
    
        // Crea o ottieni la cartella della data (es. "2024-12-06")
        $dateFolderId = $this->getOrCreateFolder($sedeFolderId, $dateFolderName);
    
        // Crea o ottieni la sottocartella (nome dinamico come "nome1", "nome2", etc.)
        $subFolderId = $this->getOrCreateFolder($dateFolderId, $subFolderName);
    
        // URL per caricare il file
        $url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
    
        // Definisci il boundary
        $boundary = uniqid("boundary_");
        $eol = "\r\n";
        $delimiter = "--" . $boundary;
    
        // Metadati del file
        $metadata = [
            "name" => $fileName,
            "parents" => [$subFolderId]
        ];
    
        // Corpo multipart
        $body = 
            $delimiter . $eol .
            "Content-Type: application/json; charset=UTF-8" . $eol . $eol .
            json_encode($metadata) . $eol .
            $delimiter . $eol .
            "Content-Type: $mimeType" . $eol . 
            "Content-Transfer-Encoding: binary" . $eol . $eol .
            $fileContent . $eol .
            $delimiter . "--";
    
        // Intestazioni della richiesta
        $headers = [
            "Authorization: Bearer " . $this->accessToken,
            "Content-Type: multipart/related; boundary=$boundary",
            "Content-Length: " . strlen($body)
        ];
    
        // Invia la richiesta con cURL
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    
        $response = curl_exec($ch);
    
        if (curl_errno($ch)) {
            Notification::display_notification("Errore cURL: " . curl_error($ch), 'error', 'Errore');
            return false;
        }
    
        $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($httpStatus !== 200 && $httpStatus !== 201) {
            Notification::display_notification("Errore API Google Drive: " . $response, 'error', 'Errore');
            return false;
        }
    
        curl_close($ch);
    
        return true;
    }
    
    

    public function getOrCreateFolder(string $parentId = null, string $folderName)
    {
        if (empty($folderName)) {
            throw new InvalidArgumentException("Il nome della cartella non può essere vuoto.");
        }
    
        // Parametri di ricerca per la cartella
        $q = "name='" . addslashes($folderName) . "' and mimeType='application/vnd.google-apps.folder'";
        if ($parentId) {
            $q .= " and '" . $parentId . "' in parents";
        }
    
        // URL per ottenere la lista dei file
        $url = "https://www.googleapis.com/drive/v3/files?q=" . urlencode($q) . "&spaces=drive&fields=files(id,name)";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: Bearer " . $this->accessToken,
            "Accept: application/json"
        ]);
    
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);
        curl_close($ch);
    
        if ($response === false) {
            throw new RuntimeException("Errore cURL (GET): " . $curlError);
        }
    
        $decodedResponse = json_decode($response, true);
    
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new RuntimeException("Errore di decodifica JSON (GET): " . json_last_error_msg());
        }
    
        if ($httpCode >= 400) {
            $errorMessage = $decodedResponse['error']['message'] ?? 'Errore sconosciuto';
            throw new RuntimeException("Errore API (HTTP $httpCode) (GET): $errorMessage");
        }
    
        if (!empty($decodedResponse['files'])) {
            // Se la cartella esiste, restituisci il suo ID
            return $decodedResponse['files'][0]['id'];
        } 
    
        // Se la cartella non esiste, crea una nuova cartella
        $folderMetadata = [
            'name' => $folderName,
            'mimeType' => 'application/vnd.google-apps.folder',
        ];
    
        if ($parentId) {
            $folderMetadata['parents'] = [$parentId];
        }
    
        $url = "https://www.googleapis.com/drive/v3/files";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($folderMetadata));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: Bearer " . $this->accessToken,
            "Content-Type: application/json",
            "Accept: application/json"
        ]);
    
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);
        curl_close($ch);
    
        if ($response === false) {
            throw new RuntimeException("Errore cURL (POST): " . $curlError);
        }
    
        $decodedResponse = json_decode($response, true);
    
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new RuntimeException("Errore di decodifica JSON (POST): " . json_last_error_msg());
        }
    
        if ($httpCode >= 400) {
            $errorMessage = $decodedResponse['error']['message'] ?? 'Errore sconosciuto';
            throw new RuntimeException("Errore API (HTTP $httpCode) (POST): $errorMessage");
        }
    
        if (!isset($decodedResponse['id'])) {
            throw new RuntimeException("Impossibile creare la cartella '{$folderName}'");
        }
    
        return $decodedResponse['id'];
    }
    
    
    


}
