<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\Collection;
use App\Models\CollectionDailyStat;
use App\Services\ThumbnailPresenter;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

class CollectionAnalyticsService
{
    public function snapshot(Collection $collection, ?Carbon $date = null): void
    {
        $bucket = ($date ?? now())->toDateString();

        DB::table('collection_daily_stats')->updateOrInsert(
            [
                'collection_id' => $collection->id,
                'stat_date' => $bucket,
            ],
            [
                'views_count' => (int) $collection->views_count,
                'likes_count' => (int) $collection->likes_count,
                'follows_count' => (int) $collection->followers_count,
                'saves_count' => (int) $collection->saves_count,
                'comments_count' => (int) $collection->comments_count,
                'shares_count' => (int) $collection->shares_count,
                'submissions_count' => (int) $collection->submissions()->count(),
                'created_at' => now(),
                'updated_at' => now(),
            ]
        );
    }

    public function overview(Collection $collection, int $days = 30): array
    {
        $rows = CollectionDailyStat::query()
            ->where('collection_id', $collection->id)
            ->where('stat_date', '>=', now()->subDays(max(7, $days - 1))->toDateString())
            ->orderBy('stat_date')
            ->get();

        $first = $rows->first();
        $last = $rows->last();

        $delta = static fn (string $column): int => max(0, (int) ($last?->{$column} ?? 0) - (int) ($first?->{$column} ?? 0));

        return [
            'totals' => [
                'views' => (int) $collection->views_count,
                'likes' => (int) $collection->likes_count,
                'follows' => (int) $collection->followers_count,
                'saves' => (int) $collection->saves_count,
                'comments' => (int) $collection->comments_count,
                'shares' => (int) $collection->shares_count,
                'submissions' => (int) $collection->submissions()->count(),
            ],
            'range' => [
                'days' => $days,
                'views_delta' => $delta('views_count'),
                'likes_delta' => $delta('likes_count'),
                'follows_delta' => $delta('follows_count'),
                'saves_delta' => $delta('saves_count'),
                'comments_delta' => $delta('comments_count'),
            ],
            'timeline' => $rows->map(fn (CollectionDailyStat $row) => [
                'date' => $row->stat_date?->toDateString(),
                'views' => (int) $row->views_count,
                'likes' => (int) $row->likes_count,
                'follows' => (int) $row->follows_count,
                'saves' => (int) $row->saves_count,
                'comments' => (int) $row->comments_count,
                'shares' => (int) $row->shares_count,
                'submissions' => (int) $row->submissions_count,
            ])->values()->all(),
            'top_artworks' => $this->topArtworks($collection),
        ];
    }

    public function topArtworks(Collection $collection, int $limit = 8): array
    {
        return DB::table('collection_artwork as ca')
            ->join('artworks as a', 'a.id', '=', 'ca.artwork_id')
            ->leftJoin('artwork_stats as s', 's.artwork_id', '=', 'a.id')
            ->where('ca.collection_id', $collection->id)
            ->whereNull('a.deleted_at')
            ->orderByDesc(DB::raw('COALESCE(s.ranking_score, 0)'))
            ->orderByDesc(DB::raw('COALESCE(s.views, 0)'))
            ->limit(max(1, min($limit, 12)))
            ->get([
                'a.id',
                'a.title',
                'a.slug',
                'a.hash',
                'a.thumb_ext',
                DB::raw('COALESCE(s.views, 0) as views'),
                DB::raw('COALESCE(s.favorites, 0) as favourites'),
                DB::raw('COALESCE(s.shares_count, 0) as shares'),
                DB::raw('COALESCE(s.ranking_score, 0) as ranking_score'),
            ])
            ->map(fn ($row) => [
                'id' => (int) $row->id,
                'title' => (string) $row->title,
                'slug' => (string) $row->slug,
                'thumb' => $row->hash && $row->thumb_ext ? ThumbnailPresenter::forHash((string) $row->hash, (string) $row->thumb_ext, 'sq') : null,
                'views' => (int) $row->views,
                'favourites' => (int) $row->favourites,
                'shares' => (int) $row->shares,
                'ranking_score' => round((float) $row->ranking_score, 2),
            ])
            ->values()
            ->all();
    }
}
