<?php

namespace App\Jobs\Contact;

use App\Models\Client\Client;
use App\Models\Contact\Hub\ContactMessage;
use App\Models\Task;
use App\Services\HistoryService;
use App\Services\TaskService;
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\Log;
use Illuminate\Support\Str;

/**
 * When an inbound email is linked to a client file — automatically by sender
 * match at ingest, or manually from the inbox — raise a task for every case
 * handler assigned to that client so the right people are notified to review it.
 *
 * Deliberately scoped to client-linked emails only. DSAR-response emails arrive
 * in a separate mailbox, are matched to a DSAR (not a Client), and are worked
 * from the /inbox/triage queues — so they are handled by the triage automation
 * and never reach this job.
 *
 * Runs on the queue (console) context, where BelongsToSolicitor does not
 * auto-scope and there is no authenticated user, so the task's solicitor is
 * supplied explicitly and it is recorded as a system-generated task.
 */
class NotifyCaseHandlersOfEmailJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $backoff = 30;

    public function __construct(
        public readonly int $messageId,
    ) {}

    public function handle(TaskService $tasks, HistoryService $history): void
    {
        $message = ContactMessage::find($this->messageId);

        if (! $message) {
            Log::warning("NotifyCaseHandlersOfEmailJob: message {$this->messageId} not found.");
            return;
        }

        // Only emails sitting on a client file. Anything matched to a DSAR (or
        // unmatched) is out of scope — those flow through the triage queues.
        if ($message->messageable_type !== Client::class || ! $message->messageable_id) {
            return;
        }

        $client = Client::find($message->messageable_id);

        if (! $client) {
            return;
        }

        // Every handler assigned to the client, de-duplicated by user (one
        // person may hold more than one handler type).
        $handlers = $client->handlers()->with('user')->get()
            ->pluck('user')
            ->filter()
            ->unique('id');

        if ($handlers->isEmpty()) {
            Log::info("NotifyCaseHandlersOfEmailJob: client {$client->id} has no handlers; no task created for message {$this->messageId}.");
            return;
        }

        $preview = $message->subject
            ?: Str::limit(trim(strip_tags($message->body_text ?: ($message->body_html ?? ''))), 120);

        $title       = 'New client email: ' . (Str::limit($preview, 60) ?: 'no subject');
        $description = 'Email received from ' . $client->fullName
            . ($message->from_email ? ' <' . $message->from_email . '>' : '')
            . '. Review and action it on the client file.';

        // Set the task due time to when the email was received.
        $dueAt = $message->created_at ?? now();

        foreach ($handlers as $user) {
            // Idempotent: never raise a second task for the same email/handler
            // (job retries, or the email being re-linked to the same client).
            $alreadyNotified = Task::withoutGlobalScope('outstanding')
                ->where('contact_message_id', $message->id)
                ->where('user_id', $user->id)
                ->exists();

            if ($alreadyNotified) {
                continue;
            }

            $tasks->addSystemTask(
                $history,
                $client,
                $user,
                $title,
                $dueAt,
                $description,
                (int) $message->solicitor_id,
                $message->id,
            );
        }

        Log::info("NotifyCaseHandlersOfEmailJob: ensured handler tasks for message {$this->messageId} (client {$client->id}, {$handlers->count()} handler(s)).");
    }
}
