<?php

declare(strict_types=1);

namespace App\Services;

use App\Events\Collections\CollectionLiked;
use App\Events\Collections\CollectionUnliked;
use App\Models\Collection;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class CollectionLikeService
{
    public function like(User $actor, Collection $collection): bool
    {
        $this->guard($actor, $collection);

        $inserted = false;

        DB::transaction(function () use ($actor, $collection, &$inserted): void {
            $rows = DB::table('collection_likes')->insertOrIgnore([
                'collection_id' => $collection->id,
                'user_id' => $actor->id,
                'created_at' => now(),
            ]);

            if ($rows === 0) {
                return;
            }

            $inserted = true;

            DB::table('collections')
                ->where('id', $collection->id)
                ->update([
                    'likes_count' => DB::raw('likes_count + 1'),
                    'last_activity_at' => now(),
                    'updated_at' => now(),
                ]);
        });

        if ($inserted) {
            event(new CollectionLiked($collection->fresh(), (int) $actor->id));
        }

        return $inserted;
    }

    public function unlike(User $actor, Collection $collection): bool
    {
        $deleted = false;

        DB::transaction(function () use ($actor, $collection, &$deleted): void {
            $rows = DB::table('collection_likes')
                ->where('collection_id', $collection->id)
                ->where('user_id', $actor->id)
                ->delete();

            if ($rows === 0) {
                return;
            }

            $deleted = true;

            DB::table('collections')
                ->where('id', $collection->id)
                ->where('likes_count', '>', 0)
                ->update([
                    'likes_count' => DB::raw('likes_count - 1'),
                    'updated_at' => now(),
                ]);
        });

        if ($deleted) {
            event(new CollectionUnliked($collection->fresh(), (int) $actor->id));
        }

        return $deleted;
    }

    public function isLiked(?User $viewer, Collection $collection): bool
    {
        if (! $viewer) {
            return false;
        }

        return DB::table('collection_likes')
            ->where('collection_id', $collection->id)
            ->where('user_id', $viewer->id)
            ->exists();
    }

    private function guard(User $actor, Collection $collection): void
    {
        if (! $collection->isPubliclyEngageable()) {
            throw ValidationException::withMessages([
                'collection' => 'Only public collections can be liked.',
            ]);
        }

        if ($collection->isOwnedBy($actor)) {
            throw ValidationException::withMessages([
                'collection' => 'You cannot like your own collection.',
            ]);
        }
    }
}
