<?php

declare(strict_types=1);

namespace App\Console\Commands;

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

/**
 * php artisan skinbase:reset-windowed-stats --period=24h|7d
 *
 * Resets / recomputes the sliding-window stats columns in artwork_stats:
 *
 *   views_24h / views_7d
 *     — Zeroed on each reset because we have no per-view event log.
 *       Artworks re-accumulate from the next view event onward.
 *       (Low-traffic reset window: 03:30 means minimal trending disruption.)
 *
 *   downloads_24h / downloads_7d
 *     — Recomputed accurately from the artwork_downloads event log.
 *       A single bulk UPDATE with a correlated COUNT() is safe here because
 *       it runs once nightly/weekly, not in the hot path.
 *
 * Scheduled in routes/console.php:
 *   --period=24h  daily at 03:30
 *   --period=7d   weekly (Monday) at 03:30
 */
class ResetWindowedStatsCommand extends Command
{
    protected $signature = 'skinbase:reset-windowed-stats
                            {--period=24h : Window to reset: 24h or 7d}';

    protected $description = 'Reset windowed view/download counters in artwork_stats';

    public function handle(): int
    {
        $period = (string) $this->option('period');

        if (! in_array($period, ['24h', '7d'], true)) {
            $this->error("Invalid period '{$period}'. Use 24h or 7d.");
            return self::FAILURE;
        }

        [$viewsCol, $downloadsCol, $cutoff] = match ($period) {
            '24h'   => ['views_24h', 'downloads_24h', now()->subDay()],
            default => ['views_7d',  'downloads_7d',  now()->subDays(7)],
        };

        $start = microtime(true);

        // ── 1. Zero the views window column ──────────────────────────────────
        //    We have no per-view event log, so we reset the accumulator.
        $viewsReset = DB::table('artwork_stats')->update([$viewsCol => 0]);

        // ── 2. Recompute downloads window from the event log ─────────────────
        //    artwork_downloads has created_at, so each row's window is accurate.
        //    Chunked PHP loop avoids MySQL-only functions (GREATEST, INTERVAL)
        //    so this command works in both MySQL (production) and SQLite (tests).
        $downloadsRecomputed = 0;

        DB::table('artwork_stats')
            ->orderBy('artwork_id')
            ->chunk(1000, function ($rows) use ($downloadsCol, $cutoff, &$downloadsRecomputed): void {
                foreach ($rows as $row) {
                    $count = DB::table('artwork_downloads')
                        ->where('artwork_id', $row->artwork_id)
                        ->where('created_at', '>=', $cutoff)
                        ->count();

                    DB::table('artwork_stats')
                        ->where('artwork_id', $row->artwork_id)
                        ->update([$downloadsCol => max(0, $count)]);

                    $downloadsRecomputed++;
                }
            });

        $elapsed = round(microtime(true) - $start, 2);

        $this->info("Period: {$period}");
        $this->info("  {$viewsCol}: zeroed {$viewsReset} rows");
        $this->info("  {$downloadsCol}: recomputed {$downloadsRecomputed} rows ({$elapsed}s)");

        Log::info('ResetWindowedStats complete', [
            'period'               => $period,
            'views_col'            => $viewsCol,
            'views_rows_reset'     => $viewsReset,
            'downloads_col'        => $downloadsCol,
            'downloads_recomputed' => $downloadsRecomputed,
            'elapsed_s'            => $elapsed,
        ]);

        return self::SUCCESS;
    }
}
