<?php

declare(strict_types=1);

namespace App\Console\Commands;

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

/**
 * Copy views and downloads from the legacy `wallz` table into `artwork_stats`.
 *
 * Uses wallz.id as artwork_id.
 * Rows that already exist are updated; missing rows are inserted with zeros
 * for all other counters.
 *
 * Usage:
 *   php artisan skinbase:migrate-wallz-stats
 *   php artisan skinbase:migrate-wallz-stats --chunk=500 --dry-run
 */
class MigrateWallzStatsCommand extends Command
{
    protected $signature = 'skinbase:migrate-wallz-stats
                            {--chunk=1000 : Number of wallz rows to process per batch}
                            {--dry-run : Preview counts without writing to the database}';

    protected $description = 'Import views and downloads from legacy wallz table into artwork_stats';

    public function handle(): int
    {
        $chunkSize = (int) $this->option('chunk');
        $dryRun    = (bool) $this->option('dry-run');

        if ($dryRun) {
            $this->warn('[DRY RUN] No data will be written.');
        }

        $total     = (int) DB::connection('legacy')->table('wallz')->count();
        $processed = 0;
        $inserted  = 0;
        $updated   = 0;

        $this->info("Found {$total} rows in legacy wallz table. Chunk size: {$chunkSize}.");

        $bar = $this->output->createProgressBar($total);
        $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%% — ins: %message%');
        $bar->setMessage('0 ins / 0 upd');
        $bar->start();

        DB::connection('legacy')
            ->table('wallz')
            ->select('id', 'views', 'dls', 'rating', 'rating_num')
            ->orderBy('id')
            ->chunk($chunkSize, function ($rows) use ($dryRun, &$processed, &$inserted, &$updated, $bar) {
                $artworkIds = $rows->pluck('id')->all();

                // Find which artwork_ids already have a stats row.
                $existing = DB::table('artwork_stats')
                    ->whereIn('artwork_id', $artworkIds)
                    ->pluck('artwork_id')
                    ->flip(); // flip → [artwork_id => index] for O(1) lookup

                $toInsert = [];
                $now      = now()->toDateTimeString();

                foreach ($rows as $row) {
                    $views      = max(0, (int) $row->views);
                    $dls        = max(0, (int) $row->dls);
                    $ratingAvg  = max(0, (float) $row->rating);
                    $ratingCount = max(0, (int) $row->rating_num);

                    if ($existing->has($row->id)) {
                        // Update existing row.
                        if (! $dryRun) {
                            DB::table('artwork_stats')
                                ->where('artwork_id', $row->id)
                                ->update([
                                    'views'        => $views,
                                    'downloads'    => $dls,
                                    'rating_avg'   => $ratingAvg,
                                    'rating_count' => $ratingCount,
                                ]);
                        }
                        $updated++;
                    } else {
                        // Batch-collect for insert.
                        $toInsert[] = [
                            'artwork_id'    => $row->id,
                            'views'         => $views,
                            'views_24h'     => 0,
                            'views_7d'      => 0,
                            'downloads'     => $dls,
                            'downloads_24h' => 0,
                            'downloads_7d'  => 0,
                            'favorites'     => 0,
                            'rating_avg'    => $ratingAvg,
                            'rating_count'  => $ratingCount,
                        ];
                        $inserted++;
                    }
                }

                if (! $dryRun && ! empty($toInsert)) {
                    DB::table('artwork_stats')->insertOrIgnore($toInsert);
                }

                $processed += count($rows);
                $bar->setMessage("{$inserted} ins / {$updated} upd");
                $bar->advance(count($rows));
            });

        $bar->finish();
        $this->newLine();

        if ($dryRun) {
            $this->warn("DRY RUN complete — would insert {$inserted}, update {$updated} ({$processed} rows scanned).");
        } else {
            $this->info("Done — inserted {$inserted}, updated {$updated} ({$processed} rows processed).");
        }

        return self::SUCCESS;
    }
}
