<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use ZipArchive;

class DownloadBackup extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'download-backup';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Download and extract backup zip file';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        if (Config::get('filesystems.disks.file-storage.driver') !== 's3') {
            $this->error('Requires to use S3 as storage driver to load in backup files');
            return self::FAILURE;
        }

        $files = collect(Storage::disk()->files('db-backup'))->sortByDesc(fn($name) => $name);
        if ($this->confirm('Download most recent backup file? ' . $files->first())) {
            $this->info("Downloading file");

            $backup_file = 'backup.zip';
            Storage::disk('local')->put($backup_file, Storage::disk('file-storage')->get($files->first()));
            $this->info("File downloaded");
            $this->extractArchive($backup_file);
        }
        return self::SUCCESS;
    }

    private function extractArchive(string $file_name): void
    {
        $zip = new ZipArchive();
        if ($zip->open(Storage::disk('local')->path($file_name)) !== true) {
            return;
        }

        for ($i = 0; $i < $zip->numFiles; $i++) {
            $filename = $zip->getNameIndex($i);
            $fileStream = $zip->getStream($filename);
            if (!$fileStream) {
                Log::debug("Unable to extract file: $filename");
            }

            // Open a writable stream to the target storage
            $outputStream = fopen(storage_path('app/db-backup/' . $filename), 'w');

            if (!$outputStream) {
                Log::debug("Unable to create output file for: $filename");
                fclose($fileStream);
                continue;
            }

            // Write the file in chunks to minimize memory usage
            while (!feof($fileStream)) {
                fwrite($outputStream, fread($fileStream, 8192)); // 8 KB chunks
            }

            fclose($fileStream);
            fclose($outputStream);

            $this->info('Extracted ' . $filename);
        }
        $zip->close();
    }
}
