<?php

namespace App\Http\Controllers\Api;

use App\Enums\ReactionType;
use App\Http\Controllers\Controller;
use App\Models\ArtworkComment;
use App\Models\ArtworkReaction;
use App\Models\CommentReaction;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

/**
 * Handles reaction toggling for artworks and comments.
 *
 * POST /api/artworks/{id}/reactions        → toggle artwork reaction
 * POST /api/comments/{id}/reactions        → toggle comment reaction
 * GET  /api/artworks/{id}/reactions        → list artwork reactions
 * GET  /api/comments/{id}/reactions        → list comment reactions
 */
class ReactionController extends Controller
{
    // ─────────────────────────────────────────────────────────────────────────
    // Artwork reactions
    // ─────────────────────────────────────────────────────────────────────────

    public function artworkReactions(Request $request, int $artworkId): JsonResponse
    {
        return $this->listReactions('artwork', $artworkId, $request->user()?->id);
    }

    public function toggleArtworkReaction(Request $request, int $artworkId): JsonResponse
    {
        $this->validateExists('artworks', $artworkId);
        $slug = $this->validateReactionSlug($request);

        return $this->toggle(
            model:   new ArtworkReaction(),
            where:   ['artwork_id' => $artworkId, 'user_id' => $request->user()->id, 'reaction' => $slug],
            countWhere: ['artwork_id' => $artworkId],
            entityId: $artworkId,
            entityType: 'artwork',
            userId: $request->user()->id,
            slug: $slug,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Comment reactions
    // ─────────────────────────────────────────────────────────────────────────

    public function commentReactions(Request $request, int $commentId): JsonResponse
    {
        return $this->listReactions('comment', $commentId, $request->user()?->id);
    }

    public function toggleCommentReaction(Request $request, int $commentId): JsonResponse
    {
        // Make sure comment exists and belongs to a public artwork
        $comment = ArtworkComment::with('artwork')
            ->where('id', $commentId)
            ->whereHas('artwork', fn ($q) => $q->public()->published())
            ->firstOrFail();

        $slug = $this->validateReactionSlug($request);

        return $this->toggle(
            model:      new CommentReaction(),
            where:      ['comment_id' => $commentId, 'user_id' => $request->user()->id, 'reaction' => $slug],
            countWhere: ['comment_id' => $commentId],
            entityId:   $commentId,
            entityType: 'comment',
            userId:     $request->user()->id,
            slug:       $slug,
        );
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Shared internals
    // ─────────────────────────────────────────────────────────────────────────

    private function toggle(
        \Illuminate\Database\Eloquent\Model $model,
        array  $where,
        array  $countWhere,
        int    $entityId,
        string $entityType,
        int    $userId,
        string $slug,
    ): JsonResponse {
        $table    = $model->getTable();
        $existing = DB::table($table)->where($where)->first();

        if ($existing) {
            // Toggle off
            DB::table($table)->where($where)->delete();
            $active = false;
        } else {
            // Toggle on
            DB::table($table)->insertOrIgnore(array_merge($where, [
                'created_at' => now(),
            ]));
            $active = true;
        }

        // Return fresh totals per reaction type
        $totals = $this->getTotals($table, $countWhere, $userId);

        return response()->json([
            'entity_type' => $entityType,
            'entity_id'   => $entityId,
            'reaction'    => $slug,
            'active'      => $active,
            'totals'      => $totals,
        ]);
    }

    private function listReactions(string $entityType, int $entityId, ?int $userId): JsonResponse
    {
        if ($entityType === 'artwork') {
            $table = 'artwork_reactions';
            $where = ['artwork_id' => $entityId];
        } else {
            $table = 'comment_reactions';
            $where = ['comment_id' => $entityId];
        }

        $totals = $this->getTotals($table, $where, $userId);

        return response()->json([
            'entity_type' => $entityType,
            'entity_id'   => $entityId,
            'totals'      => $totals,
        ]);
    }

    /**
     * Return per-slug totals and whether the current user has each reaction.
     */
    private function getTotals(string $table, array $where, ?int $userId): array
    {
        $rows = DB::table($table)
            ->where($where)
            ->selectRaw('reaction, COUNT(*) as total')
            ->groupBy('reaction')
            ->get()
            ->keyBy('reaction');

        $totals = [];
        foreach (ReactionType::cases() as $type) {
            $slug  = $type->value;
            $count = (int) ($rows[$slug]->total ?? 0);

            // Check if current user has this reaction
            $mine = false;
            if ($userId && $count > 0) {
                $mine = DB::table($table)
                    ->where($where)
                    ->where('reaction', $slug)
                    ->where('user_id', $userId)
                    ->exists();
            }

            $totals[$slug] = [
                'emoji' => $type->emoji(),
                'label' => $type->label(),
                'count' => $count,
                'mine'  => $mine,
            ];
        }

        return $totals;
    }

    private function validateReactionSlug(Request $request): string
    {
        $request->validate([
            'reaction' => ['required', 'string', 'in:' . implode(',', ReactionType::values())],
        ]);

        return $request->input('reaction');
    }

    private function validateExists(string $table, int $id): void
    {
        if (! DB::table($table)->where('id', $id)->exists()) {
            throw new ModelNotFoundException("No [{$table}] record found with id [{$id}].");
        }
    }
}
