<?php

namespace App\Jobs;

use App\Models\ForumPost;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

// ══════════════════════════════════════════════════════════════════
//  InPractice — NotifyForumPost Job
//  Location: app/Jobs/NotifyForumPost.php
//
//  Runs in the background after a forum post is created.
//  Never runs inside the HTTP request — always queued.
//
//  Logic:
//    - visibility = 'all'  → notify ALL active members with notify_forum = true
//                            except the post author
//    - visibility = 'hub'  → notify only members of that hub
//                            with notify_forum = true
//                            except the post author
//
//  Performance:
//    - Uses chunk(200) — never loads all users into memory at once
//    - Inserts notifications in bulk per chunk — one INSERT per 200 users
//    - No N+1 queries
//
//  Bible compliance:
//    - Dispatched to 'notifications' queue — never synchronous
//    - Stores nickname only — never real name
//    - Respects notify_forum user preference
// ══════════════════════════════════════════════════════════════════

class NotifyForumPost implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * How many times to retry if the job fails.
     */
    public int $tries = 3;

    public function __construct(
        private readonly ForumPost $post
    ) {}

    public function handle(): void
    {
        // Reload post with author and hub — may have been created milliseconds ago
        $post = $this->post->load(['user:id,nickname', 'hub:id,name_en,name_ar']);

        // Build the notification payload — same for all recipients
        $type    = 'forum_post';
        $payload = json_encode([
            'type'       => $type,
            'post_id'    => $post->id,
            'post_title' => $post->title,
            'actor'      => $post->user->nickname,   // nickname only — never real name
            'hub_en'     => $post->hub->name_en,
            'hub_ar'     => $post->hub->name_ar,
            'link'       => '/app/forum/' . $post->id,
        ]);

        $now = now();

        // ── Build recipient query ──────────────────────────────
        $query = User::where('id', '!=', $post->user_id)   // not the author
                     ->where('is_active', true)
                     ->where('notify_forum', true);

        // Hub-only post → restrict to hub members
        if ($post->visibility === 'hub') {
            $query->whereHas('hubs', fn ($q) => $q->where('hubs.id', $post->hub_id));
        }

        // ── Chunk to avoid memory issues on large member bases ─
        $query->select('id')->chunk(200, function ($users) use ($type, $payload, $now) {
            $rows = $users->map(fn ($user) => [
                'id'               => Str::uuid()->toString(),
                'notifiable_type'  => 'App\\Models\\User',
                'notifiable_id'    => $user->id,
                'type'             => $type,
                'data'             => $payload,
                'read_at'          => null,
                'created_at'       => $now,
                'updated_at'       => $now,
            ])->toArray();

            // One bulk INSERT per chunk — not one query per user
            DB::table('notifications')->insert($rows);
        });
    }
}
