<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\Notification;
use App\Models\User;
use App\Support\AvatarUrl;
use Illuminate\Support\Collection;

final class NotificationService
{
    public function listForUser(User $user, int $page = 1, int $perPage = 20): array
    {
        $resolvedPage = max(1, $page);
        $resolvedPerPage = max(1, min(50, $perPage));

        $notifications = $user->notifications()
            ->latest()
            ->paginate($resolvedPerPage, ['*'], 'page', $resolvedPage);

        $actorIds = collect($notifications->items())
            ->map(function (Notification $notification): ?int {
                $data = is_array($notification->data) ? $notification->data : [];

                return isset($data['actor_id']) ? (int) $data['actor_id'] : null;
            })
            ->filter()
            ->unique()
            ->values();

        $actors = $actorIds->isEmpty()
            ? collect()
            : User::query()
                ->with('profile:user_id,avatar_hash')
                ->whereIn('id', $actorIds->all())
                ->get()
                ->keyBy('id');

        return [
            'data' => collect($notifications->items())
                ->map(fn (Notification $notification) => $this->mapNotification($notification, $actors))
                ->values()
                ->all(),
            'unread_count' => $user->unreadNotifications()->count(),
            'meta' => [
                'total' => $notifications->total(),
                'current_page' => $notifications->currentPage(),
                'last_page' => $notifications->lastPage(),
                'per_page' => $notifications->perPage(),
            ],
        ];
    }

    public function markAllRead(User $user): void
    {
        $user->unreadNotifications()->update(['read_at' => now()]);
    }

    public function markRead(User $user, string $id): void
    {
        $notification = $user->notifications()->findOrFail($id);
        $notification->markAsRead();
    }

    private function mapNotification(Notification $notification, Collection $actors): array
    {
        $data = is_array($notification->data) ? $notification->data : [];
        $actorId = isset($data['actor_id']) ? (int) $data['actor_id'] : null;
        $actor = $actorId ? $actors->get($actorId) : null;

        return [
            'id' => (string) $notification->id,
            'type' => (string) ($data['type'] ?? $notification->type ?? 'notification'),
            'message' => (string) ($data['message'] ?? 'New activity'),
            'url' => $data['url'] ?? null,
            'created_at' => $notification->created_at?->toIso8601String(),
            'time_ago' => $notification->created_at?->diffForHumans(),
            'read' => $notification->read_at !== null,
            'actor' => $actor ? [
                'id' => (int) $actor->id,
                'name' => $actor->name,
                'username' => $actor->username,
                'avatar_url' => AvatarUrl::forUser((int) $actor->id, $actor->profile?->avatar_hash, 64),
                'profile_url' => $actor->username ? '/@' . $actor->username : null,
            ] : null,
        ];
    }
}