<?php

namespace App\Console\Commands;

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

/**
 * Collect hourly metric snapshots for artworks.
 *
 * Runs on cron every hour. Inserts a row per artwork into
 * artwork_metric_snapshots_hourly with the current totals.
 * Deltas are computed by the heat recalculation command.
 *
 * Usage:  php artisan nova:metrics-snapshot-hourly
 *         php artisan nova:metrics-snapshot-hourly --days=30 --chunk=500 --dry-run
 */
class MetricsSnapshotHourlyCommand extends Command
{
    protected $signature = 'nova:metrics-snapshot-hourly
                            {--days=60 : Only snapshot artworks created within this many days}
                            {--chunk=1000 : Chunk size for DB queries}
                            {--dry-run : Log what would be written without persisting}';

    protected $description = 'Collect hourly metric snapshots for rising/heat calculation';

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

        $this->info("[nova:metrics-snapshot-hourly] bucket={$bucketHour->toDateTimeString()} days={$days} chunk={$chunk}" . ($dryRun ? ' (dry-run)' : ''));

        $snapshotCount = 0;
        $skipCount     = 0;

        // Query artworks eligible for snapshotting:
        // - created within $days OR has a ranking_score above 0
        // First collect eligible IDs, then process in chunks
        $eligibleIds = DB::table('artworks')
            ->leftJoin('artwork_stats as s', 's.artwork_id', '=', 'artworks.id')
            ->where(function ($q) use ($days) {
                $q->where('artworks.created_at', '>=', now()->subDays($days))
                  ->orWhere(function ($q2) {
                      $q2->whereNotNull('s.ranking_score')
                          ->where('s.ranking_score', '>', 0);
                  });
            })
            ->whereNull('artworks.deleted_at')
            ->where('artworks.is_approved', true)
            ->pluck('artworks.id');

        if ($eligibleIds->isEmpty()) {
            $this->info('No eligible artworks found.');
            return self::SUCCESS;
        }

        foreach ($eligibleIds->chunk($chunk) as $chunkIds) {
            $artworkIds = $chunkIds->values()->all();

            $stats = DB::table('artwork_stats')
                ->whereIn('artwork_id', $artworkIds)
                ->get()
                ->keyBy('artwork_id');

            $rows = [];
            foreach ($artworkIds as $artworkId) {
                $stat = $stats->get($artworkId);

                $rows[] = [
                    'artwork_id'       => $artworkId,
                    'bucket_hour'      => $bucketHour,
                    'views_count'      => (int) ($stat?->views ?? 0),
                    'downloads_count'  => (int) ($stat?->downloads ?? 0),
                    'favourites_count' => (int) ($stat?->favorites ?? 0),
                    'comments_count'   => (int) ($stat?->comments_count ?? 0),
                    'shares_count'     => (int) ($stat?->shares_count ?? 0),
                    'created_at'       => now(),
                ];
            }

            if ($dryRun) {
                $snapshotCount += count($rows);
                continue;
            }

            if (!empty($rows)) {
                // Upsert: if (artwork_id, bucket_hour) already exists, update totals
                DB::table('artwork_metric_snapshots_hourly')->upsert(
                    $rows,
                    ['artwork_id', 'bucket_hour'],
                    ['views_count', 'downloads_count', 'favourites_count', 'comments_count', 'shares_count']
                );

                $snapshotCount += count($rows);
            }
        }

        $this->info("Snapshots written: {$snapshotCount} | Skipped: {$skipCount}");

        Log::info('[nova:metrics-snapshot-hourly] completed', [
            'bucket'    => $bucketHour->toDateTimeString(),
            'written'   => $snapshotCount,
            'skipped'   => $skipCount,
            'dry_run'   => $dryRun,
        ]);

        return self::SUCCESS;
    }
}
