<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use App\Models\User;
use App\Models\Company;
use App\Models\CabinClass;
use App\Models\Product;
use App\Models\Folder;
use App\Models\Document;
use App\Models\UserNotification;
use App\Events\UserNotificationEvent;

use App\Events\NotificationEvent;
use App\Models\AdminNotification;
use App\Events\AdminNotificationEvent;

use League\Flysystem\Filesystem;
use Aws\S3\S3Client;
use League\Flysystem\AwsS3v3\AwsS3V3Adapter;

class FileController extends Controller
{

    private $bucket_name;
    private $local_adapter;
    private $client;
    private $s3_adapter;
    private $s3;
    private $local;
    private $manager;

    private $local_store;

    public function __construct()
    {
        //
        $this->middleware('auth:admin');

        $this->local_store = 'fake_s3';

        $adminUser = auth()->guard('admin')->user();

        if (!$adminUser)
        {
            return response()->json(['error' => 'Unauthorized.'], 401);
        }

        /**
         * LOCAL + STORE (S3 like)
         */
        $this->bucket_name = env('AWS_BUCKET');
        $this->local_adapter = new \League\Flysystem\Local\LocalFilesystemAdapter(
            // Determine root directory
            __DIR__.'/'
        );

        $this->client = new \Aws\S3\S3Client([
            'endpoint' => env('AWS_URL'),
            'credentials' => [
                'key'    => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
            ],
            'region' => env('AWS_DEFAULT_REGION'),
            'version' => 'latest',
        ]);

        // The internal adapter
        $this->s3_adapter = new \League\Flysystem\AwsS3V3\AwsS3V3Adapter(
            // S3Client
            $this->client,
            // Bucket name
            $this->bucket_name
        );

        $this->s3 = new \League\Flysystem\Filesystem($this->s3_adapter);
        $this->local = new \League\Flysystem\Filesystem($this->local_adapter);

        // Add them in the constructor
        $manager = new \League\Flysystem\MountManager([
            'local' => $this->local,
            's3' => $this->s3,
        ]);


    }

    public function index(Request $request) {

        $items = [];

        $dirs = Storage::disk($this->local_store)->directories('/');
        $files = Storage::disk($this->local_store)->files('/');

        foreach ($dirs as $index => $dir) {
            $folder = Folder::where('path', $this->pathFromUrl(Storage::disk($this->local_store)->url($dir)))->first();

            if (!$folder)
            {
                $folder = Folder::create(['path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($dir))]);
            }

            array_push($items, [
                'name' => basename($dir),
                'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($dir)),
                'folder_id' => $folder->id,
                'type' => 'folder'
            ]);

        }

        foreach ($files as $index => $file) {
            array_push($items, [
                'name' => basename($file),
                'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($file)),
                'type' => 'file'
            ]);
        }

        $res = [
            'parent' => '/',
            'items' => $items
        ];

        return response()->json(['parent' => '/', 'items' => $items]);

    }

    public function show(Request $request) {

        $items = [];
        $path = $this->pathFromUrl($request->path);
        $dirs = Storage::disk($this->local_store)->directories($path);
        $files = Storage::disk($this->local_store)->files($path);

        foreach ($dirs as $index => $dir) {
            $folder = Folder::where('path', $this->pathFromUrl(Storage::disk($this->local_store)->url($dir)))->first();

            array_push($items, [
                'name' => basename($dir),
                'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($dir)),
                'folder_id' => $folder->id,
                'type' => 'folder'
            ]);
        }

        foreach ($files as $index => $file) {
            $document = Document::where('path', $this->pathFromUrl(Storage::disk($this->local_store)->url($file)))->first();
            $serial = '';
            if ($document) {
                $product = $document->product;
                $serial = $product ? $product->serial_number : '';
            }

            array_push($items, [
                'name' => basename($file),
                'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($file)),
                'serial_number' => $serial,
                'type' => 'file'
            ]);
        }

        return response()->json(['parent' => $path, 'items' => $items]);

    }

    public function editLabelAndPN(Request $request)
    {
        $item = $request->item;
        $pn = $request->selected_serial;
        $year = '';
        if (isset( $request->selected_year_flag) && $request->selected_year_flag == true && isset( $request->selected_year )) {
            $year = $request->selected_year;
        }

        if ($item) {
            $document = Document::where('path', $this->pathFromUrl(Storage::disk($this->local_store)->url($item['path'])))->first();

            $document->name = $item['name'];

            if ($pn != '' && isset( $request->selected_serial_flag) && $request->selected_serial_flag == true ) {
                $pn_exist = Product::where('serial_number', $pn)->first();
                if ($pn_exist) {
                    $document->product_id = $pn_exist->id;
                }

            }

            if (isset( $request->selected_year_flag) && $request->selected_year_flag == true && $year !=  $document->year &&$year != '') {

                $path_expl = explode("/", $document->path);
                $new_path = '';
                $folder_path = '';
                $file_to_upload = '';

                // senza anno
                if (count($path_expl) == 3) {
                    $new_path = $path_expl[0]."/".$path_expl[1]."/".$year."/".$path_expl[2];
                    $folder_path = $path_expl[0]."/".$path_expl[1]."/".$year."/";
                    $file_to_upload = $path_expl[2];
                }
                // con anno
                if (count($path_expl) == 4) {
                    $new_path = $path_expl[0]."/".$path_expl[1]."/".$year."/".$path_expl[3];
                    $folder_path = $path_expl[0]."/".$path_expl[1]."/".$year."/";
                    $file_to_upload = $path_expl[3];
                }

                # var_dump($year);
                # var_dump($document->year);
                # var_dump($new_path);die();
                # $document->year = $year;

                // CHANGE PATH

                // save new file
                if(!Storage::disk($this->local_store)->exists($folder_path)){
                    Storage::disk($this->local_store)->makeDirectory($folder_path, 0775, true); //creates directory
                } 
                Storage::disk($this->local_store)->copy($document->path, $new_path); // copy file

                $destination_path = Storage::disk($this->local_store)->path($folder_path);

                $this->S3_upload($this->bucket_name, $destination_path.$file_to_upload, $this->pathFromUrl($folder_path), $file_to_upload);

                // DELETE OLD FILES

                // Local delete
                Storage::disk($this->local_store)->delete($document->path);

                if ( count( $path_expl ) == 4) {
                    $old_dir_to_check = "/".$path_expl[0]."/".$path_expl[1]."/".$path_expl[2];
                    if( Storage::disk($this->local_store)->assertDirectoryEmpty($old_dir_to_check)){

                        Storage::disk($this->local_store)->delete($old_dir_to_check);
                        // s3_delete_folder ???

                    }
                }
                
                // S3 Delete file
                $result = $this->S3_delete_file($this->bucket_name, $document->path);


                $document->path = $new_path;

            }
            # die();

            $document->save();
        }

        return response()->json(['status' => 'ok', 'info' => 'Name or/and PN updated'], 200);
    }

    public function showById($id, Request $request) {

        $items = [];

        $folder = Folder::find($id);
        if (!$folder) {
            return response()->json(['error' => 'Folder not found'], 404);
        }

        $path = $folder->path;


        $dirs = Storage::disk($this->local_store)->directories($folder->path);
        $files = Storage::disk($this->local_store)->files($folder->path);


        foreach ($dirs as $index => $dir) {

            $sub_files = Storage::disk($this->local_store)->files($dir);

            if ($sub_files) {
                foreach ($sub_files as $k => $v){ 
                    if ( count(explode("/", $v)) == 4 ) {
                        $files[] = $v;
                    }
                }
            }
            if (!$sub_files || count( explode("/", $dir) ) <= 2 ) {

                $folderPath = $this->pathFromUrl(Storage::disk($this->local_store)->url($dir));

                $folder_expl = explode("/", $folderPath);

                // if (count($folder_expl) == 3) {
                //     $folderPath = $folder_expl[0]."/".$folder_expl[1];
                // }

                $subdir = Folder::where('path', $folderPath)->first();
                # die();

                # var_dump($path);

                if (!$subdir) {
                    # return response()->json(['error' => config('app.url')], 500);
                }else{

                    $subdir->path = $dir;

                     #var_dump($folderPath);
                     #var_dump($subdir->path);
                     #var_dump($this->pathFromUrl(Storage::disk($this->local_store)->url($dir)));

                    array_push($items, [
                        'name' => basename($dir),
                        'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($dir)),
                        'folder_id' => $subdir->id,
                        'type' => 'folder'
                    ]);
                }

            }
        }
        #die('ok');

        #var_dump($items);
        #var_dump($files);die();

        foreach ($files as $index => $file) {
            $document = Document::where('path', $this->pathFromUrl(Storage::disk($this->local_store)->url($file)))->first();
            $serial = '';

            if ($document) {
                $product = $document->product;
                $serial = $product ? $product->serial_number : '';
            }
            # var_dump($this->pathFromUrl(Storage::disk($this->local_store)->url($file)));

            $path_expl = explode("/", $file);

            if (count($path_expl) == 4 ) {

                array_push($items, [
                    'name' => $path_expl[2]."/".basename($file),
                    'sub_folder' => $path_expl[2],
                    'name' => (( $document && $document->name != null) ? $document->name : $this->pathFromUrl(Storage::disk($this->local_store)->url($file)) ),
                    'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($file)),
                    'serial_number' => $serial,
                    'type' => 'file'
                ]);

            }else{
                array_push($items, [
                    'name' => basename($file),
                    'sub_folder' => '',
                    'name' => (( $document && $document->name != null) ? $document->name : $this->pathFromUrl(Storage::disk($this->local_store)->url($file)) ),
                    'path' => $this->pathFromUrl(Storage::disk($this->local_store)->url($file)),
                    'serial_number' => $serial,
                    'type' => 'file'
                ]);
            }

        }

        return response()->json(['parent' => $path, 'parent_id' => $folder->parent_id, 'company_id' => $folder->company_id, 'items' => $items]);


    }

    /**
     * Delete file on local + S3
     */
    public function delete(Request $request) {

        $path = $request->path;

        $document = Document::where('path', $path)->first();


        if ($document) {
            $document->delete();
        }

        // Local delete
        Storage::disk($this->local_store)->delete($path);
        
        // S3 Delete file
        $result = $this->S3_delete_file($this->bucket_name, $path);
        
        return response()->json($path, 200);
    }

    /**
     * Delete folder on local
     */
    public function deleteFolder($id, Request $request) 
    {

        $folder = Folder::find($id);

        if (!$folder) {
            return response()->json(['error' => 'Folder not found.'], 404);
        }

        if (Storage::disk($this->local_store)->exists($folder->path)) {
            $res = Storage::disk($this->local_store)->deleteDirectory($folder->path);
            $folder->delete();

            return response()->json(['success' => 'Folder deleted']);
        }
    }


    /**
     * Delete file on S3
     */
    private function S3_delete_file($bucket_name='', $file_to_delete='')
    {
        $result = false;
        if ($bucket_name != '' && $file_to_delete != '') {
            try {
                $result = $this->client->deleteObject(array(
                    'Bucket' => $bucket_name,
                    'Key'    => $file_to_delete
                ));
            } catch (S3Exception $e) {
              // Catch an S3 specific exception.
              echo $e->getMessage();
            }
        }
        return $result;
    }


    /**
     * S3 file listing
     */
    public function S3_list_files($bucket_name='', $prefix = '')
    {
        $all_files_and_folders = [];
        $files = [];
        if ($bucket_name != '') {
            
            $response = $this->client->listObjectsV2(array('Bucket' => $bucket_name, 'MaxKeys' => 10000, 'Prefix' => $prefix));
            $files = $response->getPath('Contents');
            $request_id = array();

            if ($files != null) {
                
                foreach ($files as $file) 
                {
                    if (strpos($file['Key'], ".file_placeholder") <= 0 && substr($file['Key'], -1) != "/" ) {
                        
                        #$filename = $file['Key'];
                        $all_files_and_folders[] = $file;
                        #print "\n\nFilename:". $filename;
                    }

                }
            }
        }

        return $all_files_and_folders;
        return $files;
    }

    /**
     * Get a list of files on S3 and local store
     */
    public function S3_check_storage()
    {
        $S3_files_and_folders = $this->S3_list_files($this->bucket_name);
        $local_files_and_folders_raw = Storage::disk($this->local_store)->allFiles("/");
        $local_files_and_folders = [];

        foreach ($local_files_and_folders_raw as $k => $v) 
        {
            $local_files_and_folders[$v] = $v;
        }

        return ['s3' => $S3_files_and_folders, 'local' => $local_files_and_folders];

    }


    public function S3_check_path(Request $request)
    {
        $type = $request->type;
        $path = $request->path;

        $storage_path = storage_path()."/app/public/";

        $content = $this->S3_list_files($this->bucket_name, $request->path);
        $local_files_and_folders = [];

        if ($type != 'file')
        {
            $local_files_and_folders_raw = Storage::disk($this->local_store)->allFiles($path);

            if ($local_files_and_folders_raw != null) {
                
                foreach ($local_files_and_folders_raw as $k => $v) 
                {
                    $local_files_and_folders[$v] = $v;
                }
            }
            #var_dump($local_files_and_folders);die();
        }


        $to_delete = [];
        $to_upload = [];
        $to_update = [];
        $same_file = [];
 
        if ($content) {
            // Il path o il file esiste
            if ($type == 'file') {
                // E' un file
                if (isset( $content[0] )) {
         
                    $s3_md5 = str_replace('"', '', $content[0]['ETag']);
                    $local_md5 = md5_file( $storage_path.$path );


                    if ($s3_md5 == $local_md5) {
                        // Stesso file
                        $same_file[ $content[0]['Key'] ] = $content[0];
                        if (array_key_exists($content[0]['Key'], $local_files_and_folders)) {
                            unset(  $local_files_and_folders[ $content[0]['Key'] ] );
                        }
                    }else{
                        // Stesso file ma aggiornato
                        $to_update[ $content[0]['Key'] ] = $content[0];
                        if (array_key_exists($content[0]['Key'], $local_files_and_folders)) {
                            unset(  $local_files_and_folders[ $content[0]['Key'] ] );
                        }
                    }

                }

            }else{
                // E' una cartella
                foreach ($content as $k => $v) 
                {
                    if (!is_dir( $storage_path.$v['Key'] ) && file_exists(  $storage_path.$v['Key'] )) {
                      
                        $s3_md5 = str_replace('"', '', $v['ETag']);
                        $local_md5 = md5_file( $storage_path.$v['Key'] );

                        # var_dump($s3_md5);
                        # var_dump($local_md5);die();

                        if ($s3_md5 == $local_md5) {
                            // Stesso file
                            $same_file[ $v['Key'] ] = $v;
                            if (array_key_exists($v['Key'], $local_files_and_folders)) {
                                unset(  $local_files_and_folders[ $v['Key'] ] );
                            }
                        }else{
                            // Stesso file ma aggiornato
                            $to_update[ $v['Key'] ] = $v;
                            if (array_key_exists($v['Key'], $local_files_and_folders)) {
                                unset(  $local_files_and_folders[ $v['Key'] ] );
                            }
                        }
                    }else{
                        // Se non esiste in locale
                        if (!file_exists( $storage_path.$v['Key'] )) {
                            $to_upload[ $v['Key'] ] = $v;
                            if (array_key_exists($v['Key'], $local_files_and_folders)) {
                                unset(  $local_files_and_folders[ $v['Key'] ] );
                            }
                        }
                    }


                }
            }
            
        }else{
            // Path o file non trovato
        }

        #var_dump($path);die();
        if ($local_files_and_folders != null) {

            foreach ($local_files_and_folders as $key => $value) {
                $to_delete[ $value ]['Key'] = $value;
            }
        }
        #var_dump($to_update);die();
        return response()->json([
            'type' => $type,
            'to_update' => $to_update,
            'to_upload' => $to_upload,
            'to_delete' => $to_delete,
            'same_file' => $same_file,
        ]);
    }

    /**
     * From S3 to local upload (New files)
     */
    public function S3_to_local_upload(Request $request)
    {
        $to_upload = $request->to_upload;
        $log_uploaded = [];
        $base_path = Storage::disk($this->local_store)->path("/");

        foreach ($to_upload as $key => $value) {


            if (substr($value, -1) != "/") {
                // OK, non è una directory
                # echo "TO UPLOAD\n";
                # echo $base_path.$value."\n";

                // Upload del file dall'S3 al local
                $file_from_s3 = $this->client->GetObject([
                    'Bucket' => $this->bucket_name,
                    'Key' => $value,
                    'SaveAs' => $base_path.$value
                ]);

                $file_saved_upload[ $base_path.$value ] = Storage::disk($this->local_store)->put($value, (string) $file_from_s3['Body']);

                // Creo l'entry nel database
                $document = Document::create([
                    'path' => $value,
                    'created_at' => date("Y-m-d H:i:s"),
                    'updated_at' => date("Y-m-d H:i:s"),
                ]);
                $document->save();

                $log_uploaded[ $base_path.$value ] = $file_saved_upload[ $base_path.$value ];

                # var_dump($document);die();
            }
        }
        return response()->json(["FILE UPLOADED:" => count($log_uploaded)], 200);
    }

    /**
     * From S3 to local update (file changed)
     */
    public function S3_to_local_update(Request $request)
    {
        $to_update = $request->to_update;
        $log_updated = [];
        $base_path = Storage::disk($this->local_store)->path("/");

        foreach ($to_update as $key => $value) {
            
            # echo "TO UPDATE\n";
            # echo $base_path.$value."\n";

            // Upload del file dall'S3 al local
            $file_from_s3 = $this->client->GetObject([
                'Bucket' => $this->bucket_name,
                'Key' => $value,
                //'SaveAs' => $base_path.$value
            ]);

            $file_saved_update[$base_path.$value] = Storage::disk($this->local_store)->put($value, (string) $file_from_s3['Body']);

            $log_updated[ $base_path.$value ] = $file_saved_update[ $base_path.$value ];

        }

        return response()->json(["FILE UPDATED:" => count($log_updated)]);
    }

    /**
     * Delete local file if there is no match on S3
     */
    public function S3_to_local_delete(Request $request)
    {
        $to_delete = $request->to_delete;
        $log_deleted = [];
        $base_path = Storage::disk($this->local_store)->path("/");

        foreach ($to_delete as $key => $value) {
           
           // Non deve essere una cartella, elimino solo file
           if(File::exists($base_path.$value) && !File::isDirectory($base_path.$value) && substr($value, -1) != "/" ) 
           {
            // Esiste

            // Cerco il file sul database
            $document = Document::where('path', $value)->first();

            if ($document) {
                // SE esiste cancello la row nel database
                $document->delete();
            }

            // ELimino il file in local
            $res = Storage::disk($this->local_store)->delete($value);

            // Log
            $log_deleted[ $value ] = $res;
            
           }
        }

        return response()->json(["FILE deleted:" => count($log_deleted)]);
    }


    public function S3_apply_force_sync_result(Request $request)
    {
        $base_path = Storage::disk($this->local_store)->path("/");

        $to_delete = $request->to_delete;
        $to_upload = $request->to_upload;
        $to_update = $request->to_update;
        $same_file = $request->same_file;

        $text_log = '';

        $dirs = Storage::allDirectories("/public");
        $dirs_on_local = [];

        foreach ($dirs as $k_dir => $v_dir) {
            $dirs_on_local[$v_dir] = $v_dir;
        }

        $files = Storage::files("/public");

         # var_dump($to_upload);
         # var_dump($dirs);
         # var_dump($files);die();


        $text_log .= "\n\n----- Applying the differences from S3 to local + database -----\n\n";
        foreach ($to_update as $key => $value) {
            
            $text_log .= "TO UPDATE\n";
            $text_log .= $base_path.$value."\n";

            // Upload del file dall'S3 al local
            $file_from_s3 = $this->client->GetObject([
                'Bucket' => $this->bucket_name,
                'Key' => $value,
                'SaveAs' => $base_path.$value
            ]);

            $file_saved_update[$base_path.$value] = Storage::disk($this->local_store)->put($value, (string) $file_from_s3['Body']);

            $log_updated[ $base_path.$value ] = $file_saved_update[ $base_path.$value ];

        }
        foreach ($to_upload as $key => $value) {


            if (substr($value, -1) != "/") {
                // OK, non è una directory
                $text_log .= "TO UPLOAD\n";
                $text_log .= $base_path.$value."\n";


                $file_dir_obj_to_sync = explode('/',$value);
                array_pop($file_dir_obj_to_sync);
                $folder_path = implode("/", $file_dir_obj_to_sync);

                // Controllo che la directory esiste
                if(!Storage::exists('public/'.$folder_path)) {

                    $folder_path_expl = explode("/", $folder_path);

                    $company_name = $folder_path_expl[0];
                    $cabin_class = ucwords(strtolower($folder_path_expl[1]));

                    if (isset($folder_path_expl[2])) {
                        $year = $folder_path_expl[2];
                    }else{
                        $year = '';
                    }
    
                    // Creao solo se cabin_class è uno dei 4
                    if ($cabin_class == 'Business' || $cabin_class == 'Economy' || $cabin_class == 'Premium Economy' || $cabin_class == 'First Class') {
                        
                        // Controllo se esiste la company
                        $company = Company::where('name', $company_name)->first();

                        if (!$company) {

                            $company = Company::create([
                                'name' => $company_name
                            ]);

                            Storage::disk('fake_s3')->makeDirectory($company->name);

                            $path = $company->name;

                            $companyFolder = Folder::create(['path' => $path]);

                            $company->folder_id = $companyFolder->id;
                            $company->active = 1;

                            $companyFolder->company_id = $company->id;

                            $company->save();


                            $notification = AdminNotification::create([
                                'cta_label' => 'New Company from CLOUD',
                            ]);
                            $notification->instigator_id = 0;
                            $notification->message = 'SYSTEM created a company '.$company->name.' from CLOUD import.';
                            $notification->href = 'companies/'.$company->id;
                            $notification->save();


                            $notification = $notification->toArray();
                            #$notification['instigator'] = $user;

                        }

                        if ($cabin_class != '') {

                            $cabin = CabinClass::create([
                                'name' => $cabin_class
                            ]);

                            $path = $company->name;
                            $companyFolder = Folder::where('path', $path)->first();

                            $cabin->company_id = $company->id;

                            Storage::disk('fake_s3')->makeDirectory($company->name.'/'.$cabin->name);

                            $folder = Folder::create([
                                'path' => $company->name.'/'.$cabin->name
                            ]);

                            if ($companyFolder) {
                                $folder->parent_id = $companyFolder->id;
                            }
                            $folder->company_id = $company->id;

                            $folder->save();

                            $cabin->save();
                        }

                        
                    }
                    Storage::makeDirectory('public/'.$folder_path, 0775, true); //creates directory
                }

                // Upload del file dall'S3 al local
                $file_from_s3 = $this->client->GetObject([
                    'Bucket' => $this->bucket_name,
                    'Key' => $value,
                    //'SaveAs' => $base_path.$value
                ]);

                $file_saved_upload[ $base_path.$value ] = Storage::disk($this->local_store)->put($value, (string) $file_from_s3['Body']);

                // Creo l'entry nel database
                $document = Document::create([
                    'path' => $value,
                    'created_at' => date("Y-m-d H:i:s"),
                    'updated_at' => date("Y-m-d H:i:s"),
                ]);
                $document->save();

                $log_uploaded[ $base_path.$value ] = $file_saved_upload[ $base_path.$value ];

                # var_dump($document);die();
            }
        }

        /**
         * REMOVE
         */
        # die("STOP");
        $log_deleted = [];
        foreach ($to_delete as $key => $value) {

            $text_log .= "TO DELETE\n";
            $text_log .= $base_path.$value."\n";
           
           // Non deve essere una cartella, elimino solo file
           if(File::exists($base_path.$value) && !File::isDirectory($base_path.$value) && substr($value, -1) != "/" ) 
           {
            // Esiste

            // Cerco il file sul database
            $document = Document::where('path', $value)->first();

            if ($document) {
                // SE esistte cancello la row nel database
                $document->delete();
            }

            // ELimino il file in local
            $res = Storage::disk($this->local_store)->delete($value);

            // Log
            $log_deleted[ $value ] = $res;
            
           }
        }

        $text_log .= "\n\n---- DONE ----\n";

        return response()->json(['log' => $text_log]);
    }

    /**
     * Discover and Syncro ( die before real syncro)
     */
    public function S3_force_sync(Request $request)
    {
        # error_reporting(E_ALL);

        $all_files = $this->S3_check_storage();
        $storage_path = storage_path()."/app/public/";

        $to_delete = [];
        $to_upload = [];
        $to_update = [];
        $same_file = [];
        
        #echo "\n---- S3 TO LACAL SYNC ----\n\n";
        #echo "---- Scanning S3 bucket ----\n";

        foreach ($all_files['s3'] as $k => $v_s3) 
        {
            if( array_key_exists($v_s3['Key'], $all_files['local']) )
            {
                // File exists
                $local_file = $all_files['local'][ $v_s3['Key'] ];

                $s3_md5 = str_replace('"', '', $v_s3['ETag']);
                $local_md5 = md5_file( $storage_path.$local_file );
                
                // If ETag != md5_file => file changed, transfer to local storage from s3
                if ( $s3_md5 != $local_md5 ) 
                {
                   # echo "FILE CHANGED: ".$v_s3['Key']."\n";
                    $to_update[ $all_files['local'][ str_replace('"', '', $v_s3['Key'] ) ] ] = $all_files['local'][ str_replace('"', '', $v_s3['Key'] ) ];
                    unset( $all_files['local'][ str_replace('"', '', $v_s3['Key'] ) ] );
                }else{
                    // Same file, notthing to do
                   # echo "SAME FILE: ".$v_s3['Key']."\n";
                    $same_file[ $all_files['local'][ str_replace('"', '', $v_s3['Key'] ) ] ] = $all_files['local'][ str_replace('"', '', $v_s3['Key'] ) ];
                    unset( $all_files['local'][ str_replace('"', '', $v_s3['Key'] ) ] );
                }
                

            }else{
                // File to add
                // echo "FILE TO ADD (FROM S3): ".$v_s3['Key']."\n";
                if (strpos($v_s3['Key'], "/www/vhosts/aviointeriors.dev1.mndrn.cloud/") > 0 ) {
                    $remove_key =  str_replace('"', '', $v_s3['Key'] );
                    unset( $all_files['local'][ $remove_key ] );
                    
                }else{

                    $remove_key =  str_replace('"', '', $v_s3['Key'] );
                    $to_upload[ $remove_key ] = $remove_key;
                    unset( $all_files['local'][ $remove_key ] );
                }
            }
        }
           
        $base_path = Storage::disk($this->local_store)->path("/");

        // File to remove, not matched on S3

        foreach ($all_files['local'] as $key => $value) 
        {
           # echo "FILE TO REMOVE: ".$key."\n";
            $to_delete[ $key ] = $key;    
        }

        // GESTIONE CREAZIONE FILE E CARTELLE E MODIFICA DB (documents)
        # var_dump($to_update);
        # var_dump($to_upload);
        # var_dump($to_delete);

        return response()->json( [
            "to_update" => $to_update,
            "to_upload" => $to_upload,
            "to_delete" => $to_delete,
            "same_file" => $same_file,
        ] );

        die('STOP');

        echo "\n\n----- Applying the differences from S3 to local + database -----\n\n";
        foreach ($to_update as $key => $value) {
            
            echo "TO UPDATE\n";
            echo $base_path.$value."\n";

            // Upload del file dall'S3 al local
            $file_from_s3 = $this->client->GetObject([
                'Bucket' => $this->bucket_name,
                'Key' => $value,
                //'SaveAs' => $base_path.$value
            ]);

            $file_saved_update[$base_path.$value] = Storage::disk($this->local_store)->put($value, (string) $file_from_s3['Body']);

            $log_updated[ $base_path.$value ] = $file_saved_update[ $base_path.$value ];

        }
        foreach ($to_upload as $key => $value) {


            if (substr($value, -1) != "/") {
                // OK, non è una directory
                echo "TO UPLOAD\n";
                echo $base_path.$value."\n";

                // Upload del file dall'S3 al local
                $file_from_s3 = $this->client->GetObject([
                    'Bucket' => $this->bucket_name,
                    'Key' => $value,
                    'SaveAs' => $base_path.$value
                ]);

                $file_saved_upload[ $base_path.$value ] = Storage::disk($this->local_store)->put($value, (string) $file_from_s3['Body']);

                // Creo l'entry nel database
                $document = Document::create([
                    'path' => $value,
                    'created_at' => date("Y-m-d H:i:s"),
                    'updated_at' => date("Y-m-d H:i:s"),
                ]);
                $document->save();

                $log_uploaded[ $base_path.$value ] = $file_saved_upload[ $base_path.$value ];

                # var_dump($document);die();
            }
        }

        /**
         * REMOVE
         */
        # die("STOP");
        $log_deleted = [];
        foreach ($to_delete as $key => $value) {
           
           // Non deve essere una cartella, elimino solo file
           if(File::exists($base_path.$value) && !File::isDirectory($base_path.$value) && substr($value, -1) != "/" ) 
           {
            // Esiste

            // Cerco il file sul database
            $document = Document::where('path', $value)->first();

            if ($document) {
                // SE esistte cancello la row nel database
                $document->delete();
            }

            // ELimino il file in local
            $res = Storage::disk($this->local_store)->delete($value);

            // Log
            $log_deleted[ $value ] = $res;
            
           }
        }

       # return response()->json( $all_files );
    }

    /**
     * S3: Delete folder
     */
    private function S3_delete_folder($bucket_name='', $folder_to_delete='')
    {

        $result = false;
        if ($bucket_name != '' && $folder_to_delete != '') {
            try {
                $result = $this->client->deleteMatchingObjects(
                    $bucket_name, 
                    '/'.$folder_to_delete, 
                    '/^'.$folder_to_delete.'//'
                );

            } catch (S3Exception $e) {
              // Catch an S3 specific exception.
              echo $e->getMessage();
            }
        }
        return $result;
    }

    /**
     * S3: Make folder
     */
    private function S3_create_folder($bucket_name='', $folder_to_create='', $acl = 'public-read')
    {

        if ($bucket_name != '' && $folder_to_create != '') {

            $result = false;
            try {

                // CREATE FOLDER
                $result = $this->client->putObject(array( 
                           'Bucket' => $bucket_name,
                           'Key'    => $folder_to_create."/",
                           'Body'   => "",
                           'ACL'    => $acl
                          ));

            } catch (S3Exception $e) {
              // Catch an S3 specific exception.
              echo $e->getMessage();
            }

            return $result;

        }else{
            return false;
        }
    }

    /**
     * S3: Upload a file, make folder if not exists
     */
    public function S3_upload($bucket_name='', $source_local_file='', $destination_path='', $file_to_upload='', $acl = 'public-read')
    {
        if ($bucket_name != '' && $destination_path != '' &&  $source_local_file != '') {
          
            $info = $this->client->doesObjectExist($bucket_name, $destination_path);
            if (!$info)
            {
                // Cartella da creare
                $result = $this->S3_create_folder($bucket_name, $destination_path);
            }

            try {
              $this->client->putObject(array(
                'Bucket'=> $bucket_name,
                'Key' =>  $destination_path."/".$file_to_upload,
                'SourceFile' => $source_local_file,
                //'StorageClass' => 'REDUCED_REDUNDANCY'
              ));

            } catch (S3Exception $e) {
              // Catch an S3 specific exception.
              echo $e->getMessage();
            }
        }else{
            return false;
        }
    }

    /**
     * LOCAL + S3 Upload
     */
    public function upload(Request $request)
    {

        $path = $this->pathFromUrl($request->path);


        if ($request->hasFile('document')) {
            $original_filename = $request->file('document')->getClientOriginalName();
            $original_filename_arr = explode('.', $original_filename);
            $file_ext = end($original_filename_arr);
            $destination_path = Storage::disk($this->local_store)->path($path);


            $document = Document::where('path', $path.'/'.$original_filename)->first();

            if (!$document) {
                $document = Document::create([
                    'path'=> $path.'/'.$original_filename,
                ]);
            }

            if ($request->serialNumber) {
                $product = Product::where('serial_number', $request->serialNumber)->first();

                if (!$product)
                {
                    $product = Product::create([
                        'serial_number' => $request->serialNumber
                    ]);
                }

                $document->product_id = $product->id;
                $document->save();

            }


            if ($request->file('document')->storeAs($path, $original_filename, $this->local_store)) {
                $companyName = explode('/', $request->path)[0];
                $subdirName = explode('/', $request->path)[1];
                $folder = Folder::where('path', $path)->first();
                $company = Company::where('name', $companyName)->first();

                if ($company && $request->isLastFile) {
                    $notification = UserNotification::create(['cta_label' => 'View Folder']);
                    $notification->company_id = $company->id;
                    $notification->message = 'An administrator uploaded '.$request->totalFiles.' file(s) to '.$subdirName.'.';
                    if ($folder)
                    {
                        $notification->href = 'documents/folder/'.$folder->id;
                    } else {
                        $notification->href = 'documents/folder/'.$company->folder_id;
                    }


                    $notification->save();

                    event(new UserNotificationEvent($company, $notification));
                }
                
                
                // AWS S3 Like
                $file_to_upload = $destination_path."/".$original_filename;
                if (file_exists( $file_to_upload )) {
                    $this->S3_upload($this->bucket_name, $file_to_upload, $path, $original_filename);
                }
                // ----

                return $this->responseRequestSuccess($original_filename);
            } else {
                return $this->responseRequestError('Cannot upload file');
            }
        } else {
            return $this->responseRequestError('File not found');
        }
    }

    public function download(Request $request) {

        return Storage::disk($this->local_store)->download('\/'.$request->path);
    }

    protected function responseRequestSuccess($ret)
    {
        return response()->json(['status' => 'success', 'data' => $ret], 200)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    }

    protected function responseRequestError($message = 'Bad request', $statusCode = 200)
    {
        return response()->json(['status' => 'error', 'error' => $message], $statusCode)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    }

    protected function pathFromUrl($path) {
        $path = str_replace(config('app.url'), '', $path);
        $path = str_replace('storage/', '', $path);
        $path = trim($path, '/');
        return $path;
    }

}
