<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Jobs\RebuildCreatorJourneyJob;
use App\Services\Profile\CreatorJourneyService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class RebuildCreatorJourneyCommand extends Command
{
    protected $signature = 'skinbase:rebuild-creator-journey
                            {user_id? : The ID of a single creator to rebuild}
                            {--all : Rebuild creator journey rows for all non-deleted users}
                            {--chunk=500 : Chunk size when --all is used}
                            {--queue : Dispatch rebuild jobs instead of rebuilding inline}';

    protected $description = 'Rebuild persisted creator journey milestones from public source data';

    public function handle(CreatorJourneyService $journeys): int
    {
        $userId = $this->argument('user_id');
        $all = (bool) $this->option('all');
        $chunk = max(1, (int) $this->option('chunk'));
        $queue = (bool) $this->option('queue');

        if ($userId !== null && $all) {
            $this->error('Provide either a user_id OR --all, not both.');

            return self::FAILURE;
        }

        if ($userId !== null) {
            return $this->rebuildSingle((int) $userId, $journeys, $queue);
        }

        if ($all) {
            return $this->rebuildAll($journeys, $chunk, $queue);
        }

        $this->error('Provide a user_id or use --all.');

        return self::FAILURE;
    }

    private function rebuildSingle(int $userId, CreatorJourneyService $journeys, bool $queue): int
    {
        if (! DB::table('users')->where('id', $userId)->exists()) {
            $this->error("User {$userId} not found.");

            return self::FAILURE;
        }

        if ($queue) {
            RebuildCreatorJourneyJob::dispatch([$userId]);
            $this->info("Queued creator journey rebuild for user #{$userId}.");

            return self::SUCCESS;
        }

        $result = $journeys->rebuildForUser($userId);

        $this->table(['Metric', 'Value'], [
            ['user_id', $userId],
            ['milestones_saved', $result['milestones_saved']],
        ]);

        return self::SUCCESS;
    }

    private function rebuildAll(CreatorJourneyService $journeys, int $chunk, bool $queue): int
    {
        $total = DB::table('users')->whereNull('deleted_at')->count();

        $this->info(sprintf(
            '%s Rebuilding creator journeys for %d users (chunk=%d)...',
            $queue ? '[QUEUE]' : '[LIVE]',
            $total,
            $chunk,
        ));

        if ($queue) {
            $dispatched = 0;

            DB::table('users')
                ->whereNull('deleted_at')
                ->orderBy('id')
                ->chunkById($chunk, function ($users) use (&$dispatched): void {
                    $ids = $users->pluck('id')->map(fn ($id): int => (int) $id)->all();
                    RebuildCreatorJourneyJob::dispatch($ids);
                    $dispatched += count($ids);
                    $this->line('  Queued chunk of ' . count($ids) . ' users (total dispatched: ' . $dispatched . ')');
                });

            $this->info("Done - {$dispatched} users queued for creator journey rebuild.");

            return self::SUCCESS;
        }

        $processed = 0;
        $bar = $this->output->createProgressBar($total);
        $bar->start();

        DB::table('users')
            ->whereNull('deleted_at')
            ->orderBy('id')
            ->chunkById($chunk, function ($users) use ($journeys, &$processed, $bar): void {
                foreach ($users as $user) {
                    $journeys->rebuildForUser((int) $user->id);
                    $processed++;
                    $bar->advance();
                }
            });

        $bar->finish();
        $this->newLine();
        $this->info("Done - {$processed} creator journeys rebuilt.");

        return self::SUCCESS;
    }
}