<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Services\Ranking\ArtworkRankingService;
use Illuminate\Console\Command;

/**
 * php artisan nova:recalculate-rankings [--chunk=500] [--sync-rank-scores] [--skip-index]
 *
 * Ranking Engine V2 — recalculates ranking_score and engagement_velocity
 * for all public, approved artworks.  Designed to run every 30 minutes.
 */
class RecalculateRankingsCommand extends Command
{
    protected $signature = 'nova:recalculate-rankings
                            {--chunk=500       : DB chunk size for batch processing}
                            {--sync-rank-scores : Also update rank_artwork_scores table with V2 formula}
                            {--skip-index       : Skip dispatching Meilisearch re-index jobs}';

    protected $description = 'Recalculate V2 ranking scores (engagement + shares + decay + authority + velocity)';

    public function __construct(private readonly ArtworkRankingService $ranking)
    {
        parent::__construct();
    }

    public function handle(): int
    {
        $chunkSize      = (int)  $this->option('chunk');
        $syncRankScores = (bool) $this->option('sync-rank-scores');
        $skipIndex      = (bool) $this->option('skip-index');

        // ── Step 1: Recalculate ranking_score + engagement_velocity ─────
        $this->info('Ranking V2: recalculating scores …');
        $start   = microtime(true);
        $updated = $this->ranking->recalculateAll($chunkSize);
        $elapsed = round(microtime(true) - $start, 2);
        $this->info("  ✓ {$updated} artworks scored in {$elapsed}s");

        // ── Step 2 (optional): Sync to rank_artwork_scores ─────────────
        if ($syncRankScores) {
            $this->info('Syncing to rank_artwork_scores …');
            $start2  = microtime(true);
            $synced  = $this->ranking->syncToRankScores($chunkSize);
            $elapsed2 = round(microtime(true) - $start2, 2);
            $this->info("  ✓ {$synced} rank scores synced in {$elapsed2}s");
        }

        // ── Step 3 (optional): Trigger Meilisearch re-index ────────────
        if (! $skipIndex) {
            $this->info('Dispatching Meilisearch index jobs …');
            $this->dispatchIndexJobs();
            $this->info('  ✓ Index jobs dispatched');
        }

        return self::SUCCESS;
    }

    /**
     * Dispatch IndexArtworkJob for artworks updated in the last 24 hours
     * (or recently scored). Keeps the search index current.
     */
    private function dispatchIndexJobs(): void
    {
        \App\Models\Artwork::query()
            ->select('id')
            ->where('is_public', true)
            ->where('is_approved', true)
            ->whereNull('deleted_at')
            ->whereNotNull('published_at')
            ->where('published_at', '>=', now()->subDays(30)->toDateTimeString())
            ->chunkById(500, function ($artworks): void {
                foreach ($artworks as $artwork) {
                    \App\Jobs\IndexArtworkJob::dispatch($artwork->id);
                }
            });
    }
}
