<?php

use WP_Arvan\OBS\Helper;
use WP_Arvan\OBS\CustomDB;
use WP_Arvan\OBS\Admin\Admin;
use WP_Arvan\OBS\Kueue\KueueCore;
use WP_Arvan\OBS\Admin\Controllers\BulkUploaderController;
use WP_Arvan\OBS\Admin\Controllers\BucketTransferController;
use WP_Arvan\OBS\Admin\Controllers\RemoveLocalFilesController;
use WP_Arvan\OBS\Admin\Controllers\EmptyCurrentBucketController;
use WP_Arvan\OBS\Admin\Controllers\BulkDownloadController;


if (defined('WP_CLI') && WP_CLI) {
    WP_CLI::add_command('ac-storage', 'AcStorageCommand'/*, [
        'shortdesc' => 'Manage AC storage options.',
        'synopsis' => [
            [
                'type' => 'flag',
                'name' => 'list',
                'description' => 'List all storage options.',
            ],
            [
                'type' => 'flag',
                'name' => 'set',
                'description' => 'Set a specific storage option.',
                'optional' => true,
            ],
            array(
                'name'        => 'hook',
                'type'        => 'positional',
                'description' => 'The key for the action or filter.',
            ),
            array(
                'name'        => 'format',
                'type'        => 'assoc',
                'description' => 'List callbacks as a table, JSON, or CSV.',
                'optional'    => true,
                'options'     => array( 'table', 'json', 'csv' ),
                'default'     => 'table',
            ),
        ],
    ]*/);
}

class AcStorageCommand{
    /**
     * prompt command
     */
    private function prompt($question){
        fwrite(STDOUT,"$question");
        return strtolower(trim(fgets(STDIN)));
    }
    /**
     * Info command
     */
    public function info() {
        $bucket_name  	= Helper::get_bucket_name();
		$storage_settings= Helper::get_storage_settings();
        $client = \WP_Arvan\OBS\S3Singletone::get_instance()->get_s3client();
        $result = $client->headBucket(['Bucket' =>$bucket_name]);

        $bytes = $result['@metadata']['headers']['x-rgw-bytes-used'];
        $object_count = $result['@metadata']['headers']['x-rgw-object-count'];
        if ($bytes < 1024) $bytes .=' Bytes';
        elseif ($bytes < 1048576) $bytes = round($bytes / 1024, 2) . ' KB';
        elseif ($bytes < 1073741824) $bytes = round($bytes / 1048576, 2) . ' MB';
        elseif ($bytes >= 1073741824) $bytes =  round($bytes / 1073741824, 2) . ' GB';
        $object_count = $result['@metadata']['headers']['x-rgw-object-count'];

        WP_CLI::success('ac-storage Provider Information');
        $items = [
            ['Endpoint URL'=>$storage_settings['endpoint-url'],
            'Region'       =>$storage_settings['region'],
            'Bucket Name'  =>$bucket_name,
            'Bucket Size'  =>"$bytes",
            'Objects Count'=>"{$object_count} Objects"]
        ];
        WP_CLI\Utils\format_items('table',$items,['Endpoint URL','Region','Bucket Name','Bucket Size','Objects Count']);
    }
    //help command
    public function help() {
        WP_CLI::success('Help for ac-storage command.');
        WP_CLI::line('');
        WP_CLI::line('Migrate to new bucket');
        WP_CLI::line('wp ac-storage migrate [Source Bucket] to [Destination Bucket]');
        WP_CLI::line('');
        WP_CLI::line('Bulk upload');
        WP_CLI::line('wp ac-storage bulk upload');
        WP_CLI::line('');
        WP_CLI::line('Delete local files');
        WP_CLI::line('wp ac-storage delete local-files');
        WP_CLI::line('');
        WP_CLI::line('Empty the current bucket');
        WP_CLI::line('wp ac-storage empty current-bucket');
        WP_CLI::line('');
        WP_CLI::line('Download');
        WP_CLI::line('wp ac-storage download-to-local');
        WP_CLI::line('');
        WP_CLI::line('Change Bucket');
        WP_CLI::line('wp ac-storage set-bucket [Bucket Name]');
        WP_CLI::line('');
        WP_CLI::line('Info');
        WP_CLI::line('wp ac-storage info');
        WP_CLI::line('');
        WP_CLI::line('Help');
        WP_CLI::line('wp ac-storage help');
    }
    /**
     * Commands for Managing S3 Objects with ArvanCloud Object Storage Plugin
     * call all command has subcommands and params
     * $args list all sub commands
     * $assoc_args list all params
     * 
     * ## SUBCOMMANDS
     * Migrate to new bucket        wp ac-storage migrate [Source Bucket] to [Destination Bucket]
     * Bulk upload                  wp ac-storage bulk upload
     * Delete local files           wp ac-storage delete local-files
     * Empty the current bucket     wp ac-storage empty current-bucket
     * Download                     wp ac-storage download-to-local
     * Change Bucket                wp ac-storage set-bucket [Bucket Name]
     * Info                         wp ac-storage info
     * Help                         wp ac-storage help
     */
    function __invoke($args, $assoc_args){
        if (empty($args) || count($args) < 1) {
            WP_CLI::error('Please provide an action');
            return;
        }
        $command = str_replace('-','_',$args[0]);
        if(method_exists($this,$command)){
            array_shift($args);
            self::$command($args, $assoc_args);
        }else
            WP_CLI::error("'$args[0]' is not a registered subcommand of 'ac-storage'. See 'wp ac-storage help' for available subcommands.");
    }
    /**
     * command set-bucket
     * subcommand [Bucket Name]:change current bucket
     */
    function set_bucket($args, $assoc_args){
        if (empty($args) || count($args) < 1) {
            WP_CLI::error('Please provide an action (e.g., "upload file").');
            return;
        }
        $client = \WP_Arvan\OBS\S3Singletone::get_instance()->get_s3client();
        $list_response = $client->listBuckets();
        $buckets       = $list_response[ 'Buckets' ];
        if( count($buckets) == 0 ) {
            WP_CLI::error('You have not any bucket in ArvanCloud, please create a bucket in ArvanCloud storage panel then refresh this page!');
            return;
        }
        $buckets = array_column($buckets,'Name');
        if(!in_array($args[0],$buckets)){
            WP_CLI::error("Bucket $args[0] not found");
            return;
        }
        if ($this->prompt('Are you sure you want to proceed? (y/N)') === 'y') {
            update_option( 'arvan-cloud-storage-bucket-name',$args[0]);
            WP_CLI::success('Bucket change success.');
        }
    }
    /**
     * command bulk
     * subcommand upload:bulk upload to cuurent bucket
     */
    function bulk($args, $assoc_args){
        if (empty($args) || count($args) < 1) {
            WP_CLI::error('Please provide an action (e.g., "upload file").');
            return;
        }
        if($args[0]=='upload'){
            $kueue_scheduler = KueueCore::get_instance();
            if( $kueue_scheduler->has_pending_job('obs_do_bulk_upload') ){
                WP_CLI::error('Bulk upload has pending job.');
                return;
            }
            $memory_db    = CustomDB::get_instance();
            $bulk_bupload = new BulkUploaderController();
            $memory_db->delete_operation(array(
                'status'=>'done'
            ));
            $memory_db->delete_operation(array(
                'operation'=>'UPLOADING_PROGRESS'
            ));
            $memory_db->delete_operation(array(
                'operation'=>'STOP_UPLOADING_PROCESS',
            ));
            $all_uploadable_attachments = $bulk_bupload->get_all_attachments_files_as_array();
            if(empty($all_uploadable_attachments)){
                WP_CLI::error('Bulk upload has no data to process.');
                return;
            }
            $files_count = count($all_uploadable_attachments);

            if ($this->prompt('Are you sure you want to proceed? (y/N)') === 'y') {
                try{
                    WP_CLI::line('Bulk upload files serialize');
                    $bucket_name = Helper::get_bucket_name();
                    foreach ($all_uploadable_attachments as $source_file) {

                        $memory_db->create_operation(array(
                            'operation'=>'UPLOAD',
                            'source'=>$bucket_name,
                            'destination'=>$source_file['is_main_attachment'],
                            'key'=>[
                                'post_id'=>$source_file['post_id'],
                                'file'   =>$source_file['file']
                            ],
                            'status'=>'pending'
                        ));
                        $total_source_files[] = $source_file['file'];
                    }

                    $task_status = array(
                        'operation'=>'UPLOADING_PROGRESS',
                        'key'=>[
                            'files_count' => $files_count,
                            'processed_files_count' => 0,
                            'task_status' => 'processing'
                        ]
                    );
                    $memory_db->create_operation($task_status);
                    $time  = 0;
                    $kueue = KueueCore::get_instance();
                
                    for ( $i = 0 ;$i < $files_count; $i++) {

                        if( 0 == ($i % $bulk_bupload::PAGE_LIMIT) ) {
                            $kueue->add_job(time() + ($time * MINUTE_IN_SECONDS), 0, 'obs_do_bulk_upload', array($i));
                            $time++;
                        }

                    }
                    $kueue_scheduler->schedule_jobs();
                }catch (Exception $e){
                    WP_CLI::line($e->getMessage());
                }
                WP_CLI::success('Bulk upload add to scheduler task and start');
            }
        }//end bulk upload

    }
    /**
     * command migrate
     * subcommand [Source Bucket] to [Destination Bucket]:move files from source buckt to destination
     */
    function migrate($args, $assoc_args){
        if (empty($args) || count($args) < 1) {
            WP_CLI::error('Please provide an action (e.g., "migrate file").');
            return;
        }
        if($args[1]=='to'){
            if ((KueueCore::get_instance())->has_pending_job('obs_do_transfer_from_source_to_destination')) {
                WP_CLI::error('Already has pending task');
                return;
            }
            $bulk_transfer = new BucketTransferController();
            $buckets = $bulk_transfer->get_bucket_list();
            $bklist  = array_column($buckets,'Name');
            $from    = sanitize_text_field($args[0]) ?? null;
            $to      = sanitize_text_field($args[2]) ?? null;
            if (empty($from) || empty($to)) {
                WP_CLI::error('Source and Destination bucket ​​cannot be empty.');
                return;
            }
            if(!in_array($from,$bklist)){
                WP_CLI::error("Bucket $from not found");
                return;
            }
            if(!in_array($to,$bklist)){
                WP_CLI::error("Bucket $to not found");
                return;
            }
            $key_count = $bulk_transfer->get_bucket_all_files_count($from);
            if($key_count<=0){
                WP_CLI::error('No data to process');
                return;
            }
            if ($from == $to) {
                WP_CLI::error('Source and destination could not be same');
                return;
            }
            if ($this->prompt('Are you sure you want to proceed? (y/N)') === 'y') {
                $memory_db = CustomDB::get_instance();
                $memory_db->delete_operation(array(
                    'operation'=>'MIGRATE',
                    'status'=>'done'
                ));
                $memory_db->delete_operation(array(
                    'operation'=>'MIGRATE_PROGRESS'
                ));
                $memory_db->delete_operation(array(
                    'operation'=>'STOP_MIGRATION_PROCESS',
                ));
                $memory_db->delete_operation(array(
                    'operation'=>'MIGRATE'
                ));
                $total_source_files = $bulk_transfer->get_bucket_all_files($from);
                $files_count = count($total_source_files);
                foreach ($total_source_files as $source_file) {
                    $memory_db->create_operation(array(
                        'operation'=>'MIGRATE',
                        'source'=>$from,
                        'destination'=>$to,
                        'key'=>$source_file,
                        'status'=>'pending'
                    ));
                }
                $task_status = array(
                    'operation'=>'MIGRATE_PROGRESS',
                    'key'=>[
                        'files_count' => $files_count,
                        'processed_files_count' => 0,
                        'task_status' => 'processing'
                    ]
                );
                $memory_db->create_operation($task_status);
                $kueue = KueueCore::get_instance();
                $time  = 0;
                for ( $i =0 ;$i < $files_count; $i++) {

                    if( 0 == ($i % $bulk_transfer::PAGE_LIMIT) ) {
                        $kueue->add_job(time() + ($time * MINUTE_IN_SECONDS), 0, 'obs_do_transfer_from_source_to_destination', array($i));
                        $time++;
                    }
                }
                $kueue->add_job(time() + (MINUTE_IN_SECONDS * $time), 0, 'obs_rewrite_file_urls', array($to));
                $kueue->schedule_jobs();
                WP_CLI::success('Migrate add to scheduler task and start');
            }            
        }//end source to destincation

    }
    /**
     * Delete command
     * --local-files subcommand:delete local files
     */
    function delete($args, $assoc_args){
        if (empty($args) || count($args) < 1) {
            WP_CLI::error('Please provide an action.');
            return;
        }
        if($args[0] == 'local-files'){
            
            $kueue_scheduler  = KueueCore::get_instance();
            if ($kueue_scheduler->has_pending_job('obs_do_bulk_remove')) {
                WP_CLI::error('Already has pending task');
                return;
            }
            $RemoveLocalFiles = new RemoveLocalFilesController();
            $memory_db = CustomDB::get_instance();
            $memory_db->delete_operation(array(
                'status' => 'done'
            ));
            $memory_db->delete_operation(array(
                'operation' => 'DELETE_PROGRESS'
            ));
            $memory_db->delete_operation(array(
                'operation' => 'STOP_DELETE_PROCESS',
            ));
            $posts = $RemoveLocalFiles->get_deletable_posts();
            $upload_dir = wp_upload_dir()['basedir'] . DIRECTORY_SEPARATOR;
            $total_source_files = [];
            foreach ($posts as $post) {

                if (!$post->should_delete)
                    continue;

                if (is_array($post->attachments) && isset($post->attachments['file'])) {

                    $file_name = $post->attachments['file'];
                    $sub_attachment_path = $upload_dir . dirname($file_name) . DIRECTORY_SEPARATOR;
                    if (file_exists($upload_dir . $file_name)) {
                        $total_source_files[] = $upload_dir . $file_name;
                    }

                    if (is_array($post->attachments['sizes'])) {
                        foreach ($post->attachments['sizes'] as $key => $value) {
                            if (file_exists($sub_attachment_path . $value['file'])) {
                                $total_source_files[] = $sub_attachment_path . $value['file'];
                            }
                        }
                    }
                }
            }
            if(empty($total_source_files)){
                WP_CLI::error('No data to process.');
                return;
            }
            if ($this->prompt('Are you sure you want to proceed? (y/N)') === 'y') {
                $memory_db->delete_operation(array(
                    'operation' => 'DELETE'
                ));
                foreach ($total_source_files as $source_file) {

                    $is_already_pending = $memory_db->get_option_by_fields(array(
                        'operation' => 'DELETE',
                        'key' => $source_file,
                        'status' => 'pending'
                    ));

                    if (is_array($is_already_pending) && (count($is_already_pending) > 0))
                        continue;

                    $memory_db->create_operation(array(
                        'operation' => 'DELETE',
                        'source' => '',
                        'destination' => '',
                        'key' => $source_file,
                        'status' => 'pending'
                    ));
                }
                $files_count = count($total_source_files);
                $task_status = array(
                    'operation' => 'DELETE_PROGRESS',
                    'key' => [
                        'files_count' => $files_count,
                        'processed_files_count' => 0,
                        'task_status' => 'processing'
                    ]
                );
                $memory_db->create_operation($task_status);
                $kueue = KueueCore::get_instance();
                $time = 0;
                for ($i = 0; $i < $files_count; $i++) {

                    if (0 == ($i % $RemoveLocalFiles::PAGE_LIMIT)) {
                        $kueue->add_job(time() + ($time * MINUTE_IN_SECONDS)+1, 0, 'obs_do_bulk_remove', array($i));
                        $time++;
                    }

                }
                $kueue_scheduler->schedule_jobs();
                WP_CLI::success('Delete local-files add to scheduler task and start');
            }
        }//end local-files

    }
    /**
     * command empty
     * subcommand current-bucket:empty current bucket
     */
    function empty($args, $assoc_args){
        if (empty($args) || count($args) < 1) {
            WP_CLI::error('Please provide an action (e.g., "empty bucket").');
            return;
        }
        if($args[0]=='current-bucket'){
            $kueue_scheduler = KueueCore::get_instance();
            if ($kueue_scheduler->has_pending_job('obs_do_empty_current_bucket')) {
                WP_CLI::error('Already has pending task');
                return;
            }
            if($this->prompt('Are you sure you want to proceed? (y/N)') === 'y'){
                $memory_db = CustomDB::get_instance();
                $memory_db->delete_operation(array(
                    'status' => 'done'
                ));
                $memory_db->delete_operation(array(
                    'operation' => 'PURGING_PROGRESS'
                ));
                $memory_db->delete_operation(array(
                    'operation' => 'STOP_PURGING_PROCESS',
                ));
                $memory_db->delete_operation(array(
                    'operation' => 'PURGE'
                ));
                $bucket = Helper::get_bucket_name();
                $empty_bucket = new EmptyCurrentBucketController();
                $all_downloadable_file_names = $empty_bucket->get_full_file_list($bucket);

                if(empty($all_downloadable_file_names)){
                    WP_CLI::error('No data to process.');
                    return;
                }

                $total_source_files = [];
                foreach ($all_downloadable_file_names as $source_file) {

                    $memory_db->create_operation(array(
                        'operation' => 'PURGE',
                        'source' => '',
                        'destination' => '',
                        'key' => $source_file,
                        'status' => 'pending'
                    ));
                    $total_source_files[] = $source_file;
                }
                $files_count = count($total_source_files);
                $task_status = array(
                    'operation' => 'PURGING_PROGRESS',
                    'key' => [
                        'files_count' => $files_count,
                        'processed_files_count' => 0,
                        'task_status' => 'processing'
                    ]
                );
                $memory_db->create_operation($task_status);
                $kueue = KueueCore::get_instance();
                $time = 0;

                for ($i = 0; $i < $files_count; $i++) {

                    if (0 == ($i % $empty_bucket::PAGE_LIMIT)) {
                        $kueue->add_job(time() + ($time * MINUTE_IN_SECONDS), 0, 'obs_do_empty_current_bucket', array($i));
                        $time++;
                    }
                }
                $kueue_scheduler->schedule_jobs();
                WP_CLI::success('Delete current-bucket add to scheduler task and start');
            }
        }//end current-bucket

    }
    /**
     * command download-to-local
     */
    
    function download_to_local($args, $assoc_args){
        $kueue_scheduler = KueueCore::get_instance();
        if( $kueue_scheduler->has_pending_job('obs_do_bulk_download') ){
            WP_CLI::error('Already has pending task');
            return;
        }
        if($this->prompt('Are you sure you want to proceed? (y/N)') === 'y'){
            $memory_db = CustomDB::get_instance();
            $memory_db->delete_operation(array(
                'status'=>'done'
            ));
            $memory_db->delete_operation(array(
                'operation'=>'DOWNLOAD'
            ));
            $memory_db->delete_operation(array(
                'operation'=>'DOWNLOADING_PROGRESS'
            ));
            $memory_db->delete_operation(array(
                'operation'=>'STOP_DOWNLOADING_PROCESS',
            ));
            $bucket = Helper::get_bucket_name();
            $bulk_download = new BulkDownloadController();
            $all_downloadable_file_names = $bulk_download->get_full_file_list($bucket);
            if(empty($all_downloadable_file_names)){
                WP_CLI::error('No data to process.');
                return;
            }

            $total_source_files = [];
            $s3client = \WP_Arvan\OBS\S3Singletone::get_instance()->get_s3client();
            foreach ($all_downloadable_file_names as $source_file) {

                $result = $s3client->getObjectTagging([
                    'Bucket' => $bucket,
                    'Key' => $source_file,
                ]);
                if(!isset($result['TagSet'][0]['Key']))
                    continue;

                $memory_db->create_operation(array(
                    'operation'=>'DOWNLOAD',
                    'source'=>'',
                    'destination'=>'',
                    'key'=>$source_file,
                    'status'=>'pending'
                ));
                $total_source_files[] = $source_file;
            }
            $files_count = count($total_source_files);
            $task_status = array(
                'operation'=>'DOWNLOADING_PROGRESS',
                'key'=>[
                    'files_count' => $files_count,
                    'processed_files_count' => 0,
                    'task_status' => 'processing'
                ]
            );

            $memory_db->create_operation($task_status);
            $kueue = KueueCore::get_instance();
            $time  = 0;
            for ( $i =0 ;$i < $files_count; $i++) {

                if( 0 == ($i % $bulk_download::PAGE_LIMIT) ) {
                    $kueue->add_job(time() + ($time * MINUTE_IN_SECONDS), 0, 'obs_do_bulk_download', array($i));
                    $time++;
                }
            }
            $kueue_scheduler->schedule_jobs();
            WP_CLI::success('Dowload to local add to scheduler task and start');
        }//end prompt bulk_download

    }
}
?>