<?php
if (!defined('ABSPATH')) {
    exit;
}

class Foxblock_Backup_Google_Drive_Service
{
    private $oauth_handler;
    private $client;
    private $service;

    public function __construct()
    {
        if (!class_exists('Foxblock_Backup_Google_OAuth_Handler')) {
            require_once dirname(__FILE__) . '/class-google-oauth-handler.php';
        }
        
        $this->oauth_handler = new Foxblock_Backup_Google_OAuth_Handler();
        $this->client = $this->oauth_handler->get_client();
        if ($this->client && $this->oauth_handler->is_connected()) {
            $this->service = new \Google\Service\Drive($this->client);
        }
    }

    public function is_ready()
    {
        return $this->client && $this->oauth_handler->is_connected() && $this->service;
    }

    public function get_oauth_handler()
    {
        return $this->oauth_handler;
    }

    /**
     * Lấy ID của thư mục, nếu chưa có thì tạo.
     */
    public function get_or_create_folder($folder_name)
    {
        if (!$this->is_ready()) return false;

        $folder_name_escaped = str_replace("'", "\'", $folder_name);
        $query = sprintf("name='%s' and mimeType='application/vnd.google-apps.folder' and trashed=false", $folder_name_escaped);
        $optParams = [
            'q' => $query,
            'spaces' => 'drive',
            'fields' => 'files(id, name)'
        ];

        try {
            $results = $this->service->files->listFiles($optParams);
            if (count($results->getFiles()) > 0) {
                return $results->getFiles()[0]->getId();
            }

            // Folder does not exist, create it
            $folderMetadata = new \Google\Service\Drive\DriveFile([
                'name' => $folder_name,
                'mimeType' => 'application/vnd.google-apps.folder'
            ]);
            
            $folder = $this->service->files->create($folderMetadata, ['fields' => 'id']);
            return $folder->getId();
        } catch (Exception $e) {
            error_log('Foxblock GDrive Folder Error: ' . $e->getMessage());
            return new WP_Error('drive_api_error', $e->getMessage());
        }
    }

    /**
     * Upload bằng resumable upload (phù hợp file lớn). Thực hiện chunk upload.
     */
    public function upload_file($file_path, $folder_name = 'Foxblock Backups')
    {
        if (!$this->is_ready()) {
            return new WP_Error('not_ready', 'Google Drive chưa được kết nối.');
        }

        if (!file_exists($file_path)) {
            return new WP_Error('file_missing', 'File không tồn tại.');
        }

        $folder_id = $this->get_or_create_folder($folder_name);
        if (is_wp_error($folder_id)) {
            return new WP_Error('folder_error', 'Lỗi thư mục Drive: ' . $folder_id->get_error_message());
        }
        if (!$folder_id) {
            return new WP_Error('folder_error', 'Không thể tạo hoặc lấy thư mục trên Drive.');
        }

        $file_name = basename($file_path);
        
        $fileMetadata = new \Google\Service\Drive\DriveFile([
            'name' => $file_name,
            'parents' => [$folder_id]
        ]);

        $chunkSizeBytes = 5 * 1024 * 1024; // 5MB
        
        $this->client->setDefer(true);
        $request = $this->service->files->create($fileMetadata);
        
        $media = new \Google\Http\MediaFileUpload(
            $this->client,
            $request,
            'application/octet-stream',
            null,
            true,
            $chunkSizeBytes
        );

        $file_size = filesize($file_path);
        $media->setFileSize($file_size);

        $attempt = 1;
        $max_attempts = 3;
        $file_id = false;

        while ($attempt <= $max_attempts && !$file_id) {
            try {
                $status = false;
                $handle = fopen($file_path, "rb");
                while (!$status && !feof($handle)) {
                    $chunk = fread($handle, $chunkSizeBytes);
                    $status = $media->nextChunk($chunk);
                }
                
                fclose($handle);

                if ($status && isset($status->id)) {
                    $file_id = $status->id;
                    break;
                }

            } catch (\Google\Service\Exception $e) {
                $error_code = $e->getCode();
                if ($attempt >= $max_attempts || !in_array($error_code, [500, 502, 503, 504])) {
                    $this->client->setDefer(false);
                    return new WP_Error('upload_error', 'Drive API Error: ' . $e->getMessage());
                }
                
                // Chuẩn bị thử lại request
                $request = $this->service->files->create($fileMetadata);
                $media = new \Google\Http\MediaFileUpload($this->client, $request, 'application/octet-stream', null, true, $chunkSizeBytes);
                $media->setFileSize($file_size);
                sleep(2); // Đợi xíu trước khi thử lại
            } catch (Exception $e) {
                if ($attempt >= $max_attempts) {
                    $this->client->setDefer(false);
                    return new WP_Error('upload_error', 'Error: ' . $e->getMessage());
                }
                sleep(2);
            }
            $attempt++;
        }
        
        $this->client->setDefer(false); 

        if ($file_id) {
            return $file_id;
        }

        return new WP_Error('upload_failed', 'Upload thất bại sau ' . $max_attempts . ' lần thử.');
    }

    /**
     * Lấy danh sách file backup trên thư mục của Google Drive
     */
    public function list_files($folder_name = 'Foxblock Backups')
    {
        if (!$this->is_ready()) {
            return new WP_Error('not_ready', 'Google Drive chưa được kết nối.');
        }

        $folder_id = $this->get_or_create_folder($folder_name);
        if (!$folder_id) {
            return new WP_Error('folder_error', 'Không thể lấy thư mục trên Drive.');
        }

        $optParams = [
            'q' => sprintf("'%s' in parents and trashed=false", $folder_id),
            'spaces' => 'drive',
            'fields' => 'files(id, name, size, createdTime, webContentLink)',
            'orderBy' => 'createdTime desc'
        ];

        try {
            $results = $this->service->files->listFiles($optParams);
            $files = [];
            foreach ($results->getFiles() as $file) {
                $files[] = [
                    'id' => $file->getId(),
                    'name' => $file->getName(),
                    'size' => $file->getSize(),
                    'createdTime' => $file->getCreatedTime(),
                    'webContentLink' => $file->getWebContentLink()
                ];
            }
            return $files;
        } catch (\Google\Service\Exception $e) {
            return new WP_Error('api_error', $e->getMessage());
        } catch (Exception $e) {
            return new WP_Error('error', $e->getMessage());
        }
    }

    /**
     * Xóa 1 file trên Google Drive
     */
    public function delete_file($file_id)
    {
        if (!$this->is_ready()) return false;
        try {
            $this->service->files->delete($file_id);
            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Tải 1 file từ Google Drive về Local Server
     */
    public function download_file($file_id, $dest_path)
    {
        if (!$this->is_ready()) return new WP_Error('not_ready', 'Google Drive chưa được kết nối.');

        try {
            $response = $this->service->files->get($file_id, ['alt' => 'media']);
            $body = $response->getBody();
            
            $out = fopen($dest_path, 'wb');
            if (!$out) return new WP_Error('file_error', 'Không thể tạo file trên máy chủ.');
            
            while (!$body->eof()) {
                fwrite($out, $body->read(1024 * 1024)); // 1MB chunk
            }
            
            fclose($out);
            return true;
        } catch (\Google\Service\Exception $e) {
            return new WP_Error('api_error', $e->getMessage());
        } catch (Exception $e) {
            return new WP_Error('error', $e->getMessage());
        }
    }
}
