<?php

namespace App\Services\Communications;

use App\Models\Client\Client;
use App\Models\Communication\Communication;
use App\Models\Task;
use App\Models\User\User;
use App\Services\HistoryService;
use App\Services\TaskService;
use Illuminate\Support\Facades\DB;

class MissedCallTaskService
{
    public function __construct(
        private readonly TaskService $tasks,
        private readonly HistoryService $history,
    ) {
    }

    /**
     * Diarise a callback for every caseworker assigned to the matched client.
     *
     * The task ids are stored in the Communication's existing meta JSON so
     * repeated Twilio callbacks remain idempotent without a schema change.
     * When a voicemail arrives, the original missed-call task is promoted to a
     * voicemail-review task instead of creating a duplicate.
     */
    public function diarise(Communication $communication, bool $hasVoicemail = false): void
    {
        DB::transaction(function () use ($communication, $hasVoicemail): void {
            $communication = Communication::query()
                ->with(['communicable', 'call.assignedAgent'])
                ->find($communication->id);

            if (! $communication?->communicable instanceof Client) {
                return;
            }

            /** @var Client $client */
            $client = $communication->communicable;
            $client->loadMissing('handlers.user');

            $caseworkers = $client->handlers
                ->pluck('user')
                ->filter()
                ->push($communication->call?->assignedAgent)
                ->filter()
                ->unique('id')
                ->values();

            if ($caseworkers->isEmpty()) {
                return;
            }

            $meta = $communication->meta ?? [];
            $taskIds = collect($meta['missed_call_task_ids'] ?? [])
                ->filter(fn ($id) => is_numeric($id))
                ->map(fn ($id) => (int) $id)
                ->values();

            [$title, $description] = $this->taskCopy($client, $hasVoicemail);

            if ($taskIds->isNotEmpty()) {
                if ($hasVoicemail) {
                    Task::query()
                        ->whereKey($taskIds)
                        ->update([
                            'title' => $title,
                            'description' => $description,
                        ]);
                }

                return;
            }

            $createdTaskIds = $caseworkers
                ->map(fn (User $caseworker) => $this->tasks->addSystemTask(
                    $this->history,
                    $client,
                    $caseworker,
                    $title,
                    now(),
                    $description,
                    (int) $client->solicitor_id,
                )->id)
                ->values()
                ->all();

            $meta['missed_call_task_ids'] = $createdTaskIds;
            $communication->update(['meta' => $meta]);
        });
    }

    private function taskCopy(Client $client, bool $hasVoicemail): array
    {
        $clientName = $client->fullName ?: 'the client';
        $clientLabel = $client->displayId . ' - ' . $clientName;

        if ($hasVoicemail) {
            return [
                'New voicemail left on ' . $clientLabel . ', review it',
                'Listen to the voicemail recording on the client file and return the call.',
            ];
        }

        return [
            'New missed call from ' . $clientLabel . ', return it',
            'The client called but the call was not answered. Return the call as soon as practicably possible.',
        ];
    }
}
