<?php

declare(strict_types=1);

namespace App\Console\Commands;

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

final class AggregateFeedAnalyticsCommand extends Command
{
    protected $signature = 'analytics:aggregate-feed {--date= : Date (Y-m-d), defaults to yesterday}';

    protected $description = 'Aggregate feed analytics into daily metrics by algo version and source';

    public function handle(): int
    {
        $date = $this->option('date')
            ? (string) $this->option('date')
            : now()->subDay()->toDateString();

        $rows = DB::table('feed_events')
            ->selectRaw('algo_version, source')
            ->selectRaw("SUM(CASE WHEN event_type = 'feed_impression' THEN 1 ELSE 0 END) AS impressions")
            ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' THEN 1 ELSE 0 END) AS clicks")
            ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds IS NOT NULL AND dwell_seconds < 5 THEN 1 ELSE 0 END) AS dwell_0_5")
            ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds >= 5 AND dwell_seconds < 30 THEN 1 ELSE 0 END) AS dwell_5_30")
            ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds >= 30 AND dwell_seconds < 120 THEN 1 ELSE 0 END) AS dwell_30_120")
            ->selectRaw("SUM(CASE WHEN event_type = 'feed_click' AND dwell_seconds >= 120 THEN 1 ELSE 0 END) AS dwell_120_plus")
            ->whereDate('event_date', $date)
            ->groupBy('algo_version', 'source')
            ->get();

        foreach ($rows as $row) {
            $algoVersion = (string) $row->algo_version;
            $source = (string) $row->source;
            $impressions = (int) ($row->impressions ?? 0);
            $clicks = (int) ($row->clicks ?? 0);

            $saves = $this->countSavesForGroup($date, $algoVersion, $source);

            $ctr = $impressions > 0 ? $clicks / $impressions : 0.0;
            $saveRate = $clicks > 0 ? $saves / $clicks : 0.0;

            DB::table('feed_daily_metrics')->updateOrInsert(
                [
                    'metric_date' => $date,
                    'algo_version' => $algoVersion,
                    'source' => $source,
                ],
                [
                    'impressions' => $impressions,
                    'clicks' => $clicks,
                    'saves' => $saves,
                    'ctr' => $ctr,
                    'save_rate' => $saveRate,
                    'dwell_0_5' => (int) ($row->dwell_0_5 ?? 0),
                    'dwell_5_30' => (int) ($row->dwell_5_30 ?? 0),
                    'dwell_30_120' => (int) ($row->dwell_30_120 ?? 0),
                    'dwell_120_plus' => (int) ($row->dwell_120_plus ?? 0),
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );
        }

        $this->info("Aggregated feed analytics for {$date}.");

        return self::SUCCESS;
    }

    private function countSavesForGroup(string $date, string $algoVersion, string $source): int
    {
        /** @var Collection<int, object{user_id:int,artwork_id:int}> $clickedPairs */
        $clickedPairs = DB::table('feed_events')
            ->select('user_id', 'artwork_id')
            ->whereDate('event_date', $date)
            ->where('event_type', 'feed_click')
            ->where('algo_version', $algoVersion)
            ->where('source', $source)
            ->groupBy('user_id', 'artwork_id')
            ->get();

        if ($clickedPairs->isEmpty()) {
            return 0;
        }

        $saves = 0;
        foreach ($clickedPairs as $pair) {
            $hasSave = DB::table('user_discovery_events')
                ->whereDate('event_date', $date)
                ->where('user_id', (int) $pair->user_id)
                ->where('artwork_id', (int) $pair->artwork_id)
                ->where('algo_version', $algoVersion)
                ->whereIn('event_type', ['favorite', 'download'])
                ->exists();

            if ($hasSave) {
                $saves++;
            }
        }

        return $saves;
    }
}
