<?php

namespace App\Console\Commands;

use Illuminate\Support\Facades\File;
use Illuminate\Console\Command;

use App\Models\User;
use App\Models\ImageNode;

class MakeImageDB extends Command
{
    /**
     * Summary of processImage
     * @param mixed $file
     * @param mixed $parentId
     * @param int $userId
     * @param string $basePath
     * @return void
     */
    private function processImage($file, ?int $parentId, int $userId, string $basePath): void{
        $ext = strtolower($file->getExtension());
        if (!in_array($ext, ['jpg', 'jpeg', 'png'])) return;

        $imageFileName = $file->getFilename();

        $relativePath = str_replace(public_path(), '', $file->getPathname());
        $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);
        $relativePath = '/' . ltrim($relativePath, '/');

        ImageNode::create([
            'user_id' => $userId,
            'parent_id' => $parentId,
            'name' => $imageFileName,
            'fs_type' => 'file',
            'fs_meta' => json_encode([
                'real_name' => $file->getPathname(),
                'symbolic_name' => $relativePath,
                'title' => pathinfo($imageFileName, PATHINFO_FILENAME),
                'description' => '',
                'copyright' => '',
                'mime_type' => File::mimeType($file->getPathname()),
                'size' => $file->getSize(),
            ]),
        ]);
    }
    /**
     * Summary of scanFolder
     * @param string $fullPath
     * @param mixed $parentId
     * @param int $userId
     * @param string $basePath
     * @return void
     */
    private function scanFolder(string $fullPath, ?int $parentId, int $userId, string $basePath): void {
        $folderName = basename($fullPath);
        $folderNode = ImageNode::create([
            'user_id' => $userId,
            'name' => $folderName,
            'fs_type' => 'folder',
            'parent_id' => $parentId,
        ]);

        foreach (File::directories($fullPath) as $subdir) {
            $this->scanFolder($subdir, $folderNode->id, $userId, $basePath);
        }

        foreach (File::files($fullPath) as $file) {
            $this->processImage($file, $folderNode->id, $userId, $basePath);
        }
    }

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'pagebuilder:make-imagedb {--testmode : Use test-imagedb folder instead of imagedb for testing}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'This command is a substitute for PolarPress image handling/uploading and administration, in order to provide the page builder with images to work with in the various page components for the pagebuilder. It will scan the public/imagedb directory, and replicate its file/folder structure in the database.';

    /**
     * Execute the console command.
     */
    public function handle() {
        // The public path to the imagedb directory. If you change this, please also make sure you update
        // the .gitignore file so you don't accidentally push garbage to the repository.
        
        // We set up a test directory just for unit testing, so we don't polute the local database, or file
        // system with test data
        $imageDbPath = $this->option('testmode')
            ? public_path('test-imagedb')
            : public_path('imagedb');

        if (!File::exists($imageDbPath) || !File::isDirectory($imageDbPath)) {
            if ($this->option('testmode')) {
                $this->error("The 'public/test-imagedb' directory does not exist.");
            } else {
                $this->error("The 'public/imagedb' directory does not exist.");
            }
            return Command::FAILURE;
        }

        // At this point, the directory exist, but we also need to make sure the directory is not empty
        $contents = File::allFiles($imageDbPath);
        $subdirs = File::directories($imageDbPath);

        if (empty($contents) && empty($subdirs)) {
            if ($this->option('testmode')) {
                $this->error("The 'public/test-imagedb' directory is empty. Nothing to index.");
            } else {
                $this->error("The 'public/imagedb' directory is empty. Nothing to index.");
            }
            return Command::FAILURE;
        }

        // To avoid dublications (and to make this simple), we're now going to reset the table and
        // truncate the data so we start on a clean slate

        $this->info("Clearing existing image nodes...");
        ImageNode::truncate();

        // The image node model requires a user relationship, so we need to make the command operator
        // select which user to act as in order to populate the database correctly

        $users = User::orderBy('name')->get();
        if ($users->isEmpty()) { // Make sure there is at least one user in the database before continuing
            $this->error("No users found in the database. Cannot continue!");
            $this->line('(Use artisan serve and npm run dev to spool up a local instance, and register a user from the web interface)');
            return Command::FAILURE;
        }

        $options = [];
        foreach ($users as $user) {
            $label = "{$user->name} ({$user->email})";
            $options[$label] = $user->id;
        }

        $selectedLabel = $this->choice(
            'Select a user to act as:',
            array_keys($options),
            array_key_first($options)
        );

        $userId = $options[$selectedLabel];

        $this->info("Selected user ID: $userId: $selectedLabel");
        $this->info("Scanning and indexing image directory...");
        
        foreach (File::directories($imageDbPath) as $dir) {
            $this->scanFolder($dir, null, $userId, $imageDbPath);
        }
    
        foreach (File::files($imageDbPath) as $file) {
            $this->processImage($file, null, $userId, $imageDbPath);
        }
    
        $this->info("Image DB creation complete.");
        return Command::SUCCESS;
    }
}
