<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Artwork;
use App\Services\ArtworkStatsService;
use App\Services\XPService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
 * POST /api/art/{id}/view
 *
 * Fire-and-forget view tracker.
 *
 * Deduplication strategy (layered):
 *   1. Session key (`art_viewed.{id}`) — prevents double-counts within the
 *      same browser session (survives page reloads).
 *   2. Route throttle (5 per 10 minutes per IP+artwork) — catches bots that
 *      don't send session cookies.
 *
 * The frontend should additionally guard with sessionStorage so it only
 * calls this endpoint once per page load.
 */
final class ArtworkViewController extends Controller
{
    public function __construct(
        private readonly ArtworkStatsService $stats,
        private readonly XPService $xp,
    ) {}

    public function __invoke(Request $request, int $id): JsonResponse
    {
        $artwork = Artwork::public()
            ->published()
            ->where('id', $id)
            ->first();

        if (! $artwork) {
            return response()->json(['error' => 'Not found'], 404);
        }

        $sessionKey = 'art_viewed.' . $id;

        // Already counted this session — return early without touching the DB.
        if ($request->hasSession() && $request->session()->has($sessionKey)) {
            return response()->json(['ok' => true, 'counted' => false]);
        }

        // Write persistent event log (auth user_id or null for guests).
        $this->stats->logViewEvent((int) $artwork->id, $request->user()?->id);

        // Defer to Redis when available, fall back to direct DB increment.
        $this->stats->incrementViews((int) $artwork->id, 1, defer: true);

        $viewerId = $request->user()?->id;
        if ($artwork->user_id !== null && (int) $artwork->user_id !== (int) ($viewerId ?? 0)) {
            $this->xp->awardArtworkViewReceived(
                (int) $artwork->user_id,
                (int) $artwork->id,
                $viewerId,
                (string) $request->ip(),
            );
        }

        // Mark this session so the artwork is not counted again.
        if ($request->hasSession()) {
            $request->session()->put($sessionKey, true);
        }

        return response()->json(['ok' => true, 'counted' => true]);
    }
}
