<?php
    if ( ! defined( 'ABSPATH' ) ) exit;
    class cloudS3Class {
        public $s3;

        public $bucket;
        public $credential = array();
    
        static function getPluginStatus(){
            if (get_option('cloud_s3_storage_status') === false) {
                add_option('cloud_s3_storage_status', 0);
            }

            return get_option('cloud_s3_storage_status');
        }

        static function setPluginStatus($new_status) {
            update_option('cloud_s3_storage_status', $new_status);
        }

        public function list_files_by_bucket($s3, $bucket_name)
        {
            if (!$s3) {
                return false;
            }

            try {
                $objects = $s3->listObjects(['Bucket' => $bucket_name]);

                $files_with_presigned_urls = [];
                foreach ($objects['Contents'] as $object) {
                    $key = $this->sanitize_key($object['Key']);
                    $presigned_url = $this->get_presigned_url($s3, $bucket_name, $key);
                    $files_with_presigned_urls[] = [
                        'key' => $key,
                        'presigned_url' => $presigned_url
                    ];
                }

                return $files_with_presigned_urls;
            } catch (Exception $e) {
                return false;
            }
        }

        public function get_public_url($s3, $bucket_name, $file_key) {
            try {
                $url = $s3->getObjectUrl($bucket_name, $file_key);
                return $url;
            } catch (Exception $e) {
                return false;
            }
        }
        
        public function get_presigned_url($s3, $bucket_name, $key, $expiration = '+1 hour') {
            try {
                $key = $this->sanitize_key($key);
                $cmd = $s3->getCommand('GetObject', [
                    'Bucket' => $bucket_name,
                    'Key'    => $key
                ]);
        
                $request = $s3->createPresignedRequest($cmd, $expiration);
                $presignedUrl = (string)$request->getUri();
        
                return $presignedUrl;
            } catch (Aws\Exception\AwsException $e) {
                return false;
            }
        }
        
        public function download_object_from_s3($s3, $bucket_name, $object_key, $local_file_path) {
            try {
                $result = $s3->getObject([
                    'Bucket' => $bucket_name,
                    'Key' => $object_key,
                    'SaveAs' => $local_file_path  
                ]);

                return $local_file_path;
            } catch (Aws\S3\Exception\S3Exception $e) {
                return false;
            }
        }

        public function get_signed_url_for_object($s3, $bucket_name, $object_key, $expiration = '+1 hour') {
            try {
                $command = $s3->getCommand('GetObject', [
                    'Bucket' => $bucket_name,
                    'Key' => $object_key
                ]);

                $request = $s3->createPresignedRequest($command, $expiration);

                $signed_url = (string)$request->getUri();

                return $signed_url;
            } catch (Aws\S3\Exception\S3Exception $e) {
                return false;
            }
        }

        static function checkParameter() {
            $options = get_option('cloud_s3_settings');
            return isset($options['access_key'], $options['secret_key'], $options['bucket_name'], $options['endpoint']);
        }

        static function getConnectionStatus() {
            $options = get_option('cloud_s3_settings');
            if(SELF::checkParameter()) {        
                $bucket = $options['bucket_name']; 
        
                try {
                    $s3 = SELF::s3Create();
        
                    $s3->listObjects(['Bucket' => $bucket]);
                    return true;
                }catch (Aws\Exception\AwsException $e) {
                    return false;
                }
            } 
            return false;
        }

        static function get_single_path_expiration ($object_key) {
            $options = get_option('cloud_s3_settings');
            $expiration = '+1 hour';

            $bucket = $options['bucket_name'];
            $object_key = self::sanitize_key_static($object_key);

            $s3 = SELF::s3Create();

            if ($s3->doesObjectExist($bucket, $object_key)) {
                $cmd = $s3->getCommand('GetObject', [
                    'Bucket' => $bucket,
                    'Key'    => $object_key
                ]);
                
                $request = $s3->createPresignedRequest($cmd, $expiration);
                $presignedUrl = (string)$request->getUri();
            
                return $presignedUrl;
            }
            return null;
        }

        static function extract_image_id_from_key($url) {
            global $wpdb;
        
            $url = strtok($url, '?');
        
            $upload_dir = wp_upload_dir();
            if (strpos($url, $upload_dir['baseurl']) !== false) {
                $url_path = str_replace($upload_dir['baseurl'], '', $url);
            } else {
                $url_path = $url;
            }
        
            $attachment_id = $wpdb->get_var($wpdb->prepare(
                "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s",
                '%' . $wpdb->esc_like(ltrim($url_path, '/')) . '%'
            ));
        
            return $attachment_id ? intval($attachment_id) : false;
        }

        static function get_single_path($object_key) {
            global $wpdb;
            
            try {
                $options = get_option('cloud_s3_settings');
                if (!isset($options['bucket_name'])) {
                    return null;
                }
        
                $bucket = $options['bucket_name'];
                
                $object_key = self::sanitize_key_static($object_key);
        
                $image_id = self::extract_image_id_from_key($object_key);
        
                if (!$image_id) {
                    $image_id = null;
                } 
        
                $status = CloudS3StorageDB::get_image_status($image_id, $object_key);
                
                if ($status === 'transferred') {
        
                    // Crea il client S3
                    $s3 = self::s3Create();
                    if (!$s3) {
                        return null;
                    }
        
                    if ($s3->doesObjectExist($bucket, $object_key)) {
                        $presignedUrl = $s3->getObjectUrl($bucket, $object_key);
                        $presignedUrl = rawurldecode($presignedUrl);
        
                        set_transient($cache_key, $presignedUrl, 3600);
        
                        return $presignedUrl;
                    } else {
                        return null;
                    }
                } else {
                    return null;
                }
            } catch (AwsException $e) {
                return null;
            } catch (Exception $e) {
                return null;
            }
        
            return null;
        }   
        
        static function getS3Files () {
            $options = get_option('cloud_s3_settings');
            $bucket = $options['bucket_name'];

            $s3 = SELF::s3Create();

            try {
                $objects = $s3->listObjects([
                    'Bucket' => $bucket
                ]);
                
                return $objects['Contents'] ? $objects['Contents'] : [];
            
            } catch (AwsException $e) {
                return [];
            }
        }

        static function downloadS3File($s3_key, $local_file_path, $ibrid = true) {
            $image_id = self::extract_image_id_from_key($local_file_path);
        
            if (!$image_id) {
                $image_id = null;
            } 

            $options = get_option('cloud_s3_settings');
            if (!isset($options['bucket_name'])) {
                return false;
            }
        
            $bucket = $options['bucket_name'];
            $upload_dir = wp_upload_dir();
            $s3 = self::s3Create();
        
            if (!$s3) {
                return false;
            }
        
            try {
                if (!$s3->doesObjectExist($bucket, $s3_key)) {
                    return false;
                }
        
                if (!$ibrid) {
                    $result = $s3->getObject([
                        'Bucket' => $bucket,
                        'Key' => $s3_key,
                        'SaveAs' => $upload_dir['basedir'] . '/' . $local_file_path
                    ]);
        
                    if (!file_exists($upload_dir['basedir'] . '/' . $local_file_path)) {
                        return false;
                    }
                }
        
                $s3->deleteObject([
                    'Bucket' => $bucket,
                    'Key' => $s3_key
                ]);

                CloudS3StorageDB::remove_image_record($image_id,$local_file_path);

                return true;
            } catch (AwsException $e) {
                return false;
            }
        }   

        static function S3_fopen($file_path) {
            global $wp_filesystem;
        
            if (empty($wp_filesystem)) {
                require_once ABSPATH . 'wp-admin/includes/file.php';
                WP_Filesystem();
            }
        
            if (!$wp_filesystem->exists($file_path)) {
                return false;
            }
        
            $file_contents = $wp_filesystem->get_contents($file_path);
            if ($file_contents === false) {
                return false;
            }
        
            return $file_contents;
        }            

        static function S3_fclose($file_temp_data) {
            if (isset($file_temp_data['path']) && file_exists($file_temp_data['path'])) {
                wp_delete_file($file_temp_data['path']);
            }
            return true;
        }              

        static function putS3File($file_path, $s3_key) {
            global $wp_filesystem;
        
            $image_id = self::extract_image_id_from_key($file_path);
            if (!$image_id) {
                $image_id = null;
            } 
        
            $options = get_option('cloud_s3_settings');
            if (!isset($options['bucket_name'])) {
                return false;
            }
        
            $bucket = $options['bucket_name'];
            $s3_key = self::sanitize_key_static($s3_key);
            $s3 = self::s3Create();
        
            if (!$s3) {
                return false;
            }
        
            try {
                $upload_dir = wp_upload_dir();
                $file_path = $upload_dir['basedir'] . '/' . $file_path;
        
                if (!$wp_filesystem->exists($file_path)) {
                    return false;
                }
        
                // Usa WP_Filesystem per leggere il contenuto del file
                $file_contents = $wp_filesystem->get_contents($file_path);
                if ($file_contents === false) {
                    return false;
                }
        
                // Carica il file su S3
                $s3->putObject([
                    'Bucket' => $bucket,
                    'Key' => $s3_key,
                    'Body' => $file_contents,
                    'ACL' => 'public-read'
                ]);
        
                CloudS3StorageDB::set_image_status($file_path, "transferred", $image_id);
        
                $presignedUrl = $s3->getObjectUrl($bucket, $s3_key);
                $presignedUrl = rawurldecode($presignedUrl);
                return $presignedUrl;
            } catch (AwsException $e) {
                return false;
            }
        }        
    
        static function s3Create () {

            $options = get_option('cloud_s3_settings');
            $credentials = [
                'key'    => $options['access_key'],
                'secret' => $options['secret_key'],
            ];

            $endpoint = $options['endpoint']; 
            $s3 = new Aws\S3\S3Client([
                'version'     => 'latest',
                'region'      => 'auto', 
                'endpoint'    => $endpoint,
                'credentials' => $credentials,
                'use_path_style_endpoint'    => true
            ]);
            return $s3;

        }

        static function getMode() {
            $options = get_option('cloud_s3_settings');
            return (!array_key_exists('active_mode', $options) || !$options['active_mode'])?false:true;
        }

        static function getModeLabel() {
            return self::getMode()?'Active':'Passive';
        }

        static function getIbridModeCheck() {
            $options = get_option('cloud_s3_settings');
            return (array_key_exists('active_bihost', $options) && $options['active_bihost'])?'OK':'NO';
        }

        private function sanitize_key($key) {
            return trim($key, '/');
        }

        private static function sanitize_key_static($key) {
            return trim($key, '/');
        }

    }
