<?php

namespace App\Actions\Communications;

use App\Enum\Contact\TemplateTriggerType;
use App\Models\Contact\ContactTemplateTrigger;
use App\ValueObjects\Communications\DispatchRequest;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class EvaluateContactTriggersAction
{
    public function __construct(
        protected DispatchContactMessageAction $dispatch,
        protected ResolveTemplateRecipientsAction $resolveRecipients,
    ) {}

    /**
     * @param array $context      condition-matching context (also stored as origin_detail)
     * @param array $placeholders extra placeholder values for rendering (merged into PlaceholderContext::extra)
     */
    public function __invoke(Model $subject, TemplateTriggerType $type, array $context = [], array $placeholders = []): void
    {
        $modelType = get_class($subject);

        $triggers = ContactTemplateTrigger::query()
            ->with(['template' => fn ($q) => $q->where('is_active', true)])
            ->where('trigger_type', $type->value)
            ->where('is_active', true)
            ->where(function ($q) use ($modelType) {
                $q->whereNull('model_type')->orWhere('model_type', $modelType);
            })
            ->get();

        foreach ($triggers as $trigger) {
            if (!$trigger->template) {
                continue;
            }
            if (!$trigger->matchesConditions($context)) {
                continue;
            }
            if (!$trigger->template->allow_automatic_send) {
                continue;
            }

            // Resolve the send-to recipient(s) from the template's recipient_type,
            // mirroring the manual composer. recipient_type = user/institution can fan
            // out to several recipients, so dispatch one message per recipient.
            $recipients = ($this->resolveRecipients)($trigger->template, $subject);

            if (empty($recipients)) {
                Log::warning('Contact trigger resolved no recipient', [
                    'trigger_id' => $trigger->id,
                    'template_id' => $trigger->contact_template_id,
                    'recipient_type' => $trigger->template->recipient_type,
                ]);
                continue;
            }

            foreach ($recipients as $recipient) {
                try {
                    $result = ($this->dispatch)(new DispatchRequest(
                        template: $trigger->template,
                        messageable: $subject,
                        recipient: $recipient,
                        origin: $type->toOrigin(),
                        originDetail: array_merge(
                            $context,
                            [
                                'trigger_id' => $trigger->id,
                                'dedupe_window_minutes' => $trigger->dedupe_window_minutes,
                            ],
                        ),
                        extraContext: $placeholders,
                    ));

                    // Surface the silent non-send outcomes (no sender, suppressed,
                    // deduped, rate-limited) so "nothing happened" is diagnosable.
                    if (!$result->queued) {
                        Log::warning('Contact trigger did not queue a message', [
                            'trigger_id'   => $trigger->id,
                            'template_id'  => $trigger->contact_template_id,
                            'reason'       => $result->reason,
                            'suppressed'   => $result->wasSuppressed,
                            'deduped'      => $result->wasDeduped,
                            'rate_limited' => $result->wasRateLimited,
                        ]);
                    }
                } catch (\Throwable $e) {
                    Log::error('Contact trigger dispatch failed', [
                        'trigger_id' => $trigger->id,
                        'template_id' => $trigger->contact_template_id,
                        'error' => $e->getMessage(),
                    ]);
                }
            }
        }
    }
}
