<?php

namespace App\Console\Commands;

use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class RemoveOrphanedSizeFiles extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'media:remove-orphaned-size-files';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Remove media sizes that do not have an original size (new file structure)';


    public function handle()
    {
        if (empty(tenant('id'))) {
            $this->output->error('Please run for a tenant');
            return self::FAILURE;
        }

        $this->processSizeFolders(tenant('id'));
        $this->processJpegFiles(tenant('id'));
        return self::SUCCESS;
    }

    /**
     * Load storage disk
     * Go through folders with Y-m format
     * Within each of these date folders find sub-folders that are not `orig`
     * And for each file in the size folder perform a check if original still exists
     * If original webp file does not exist, size should be removed
 */
    private function processSizeFolders(string $tenant): void
    {
        // Process size folders
        $disk = Storage::disk('media');
        $month = Carbon::create(2023, 5);
        do {
            $month->addMonth();
            collect($disk->directories($tenant . '/' . $month->format('Y-M')))
                ->reject(fn ($size) => Str::endsWith($size, '/orig'))
                ->each(fn ($size) => $this->processSizeFolder($size, $disk));
        } while ($month->lessThan(Carbon::now()));
    }

    private function processJpegFiles(string $tenant): void
    {
        // Process size folders
        $disk = Storage::disk('media');
        $month = Carbon::create(2023, 5);
        do {
            $month->addMonth();
            collect($disk->directories($tenant . '/' . $month->format('Y-M') . '/orig'))
                ->each(fn ($directory) => collect($disk->directories($directory))
                    ->each(fn ($subdirectory) => $this->checkAndRemoveJpeg(
                        $disk->files($subdirectory),
                        $disk
                    )));
        } while ($month->lessThan(Carbon::now()));
    }

    private function processSizeFolder(string $size, Filesystem $disk): void
    {
        $this->info('Processing size ' . $size);
        $size_parts = explode('/', $size);
        array_pop($size_parts);
        $size_parts[] = 'orig';
        $original_path = implode('/', $size_parts);
        collect($disk->directories($size))
            ->each(fn ($directory) => collect($disk->directories($directory))
                ->each(fn ($subdirectory) => $this->checkAndRemove(
                    $disk->files($subdirectory),
                    $disk,
                    $size,
                    $original_path
                )));
    }

    private function checkAndRemove(array $files, Filesystem $disk, string $size_path, string $original_path): void
    {
        foreach ($files as $file) {
            if ($disk->exists(str_replace($size_path, $original_path, $file)) === false) {
                $this->info('To remove: ' . $file);
                $disk->delete($file);
            }
        }
    }

    private function checkAndRemoveJpeg(array $files, Filesystem $disk): void
    {
        collect($files)
            ->filter(fn ($file) => Str::endsWith($file, '.jpg')
                && !in_array(str_replace('.jpg', '.webp', $file), $files))
            ->each(function ($file) use ($disk) {
                $this->info('To remove: ' . $file);
                $disk->delete($file);
            });
    }
}
