<?php

namespace App\Listeners;

use App\Events\ActivityDecisionApplied;
use App\Jobs\RunDecisionEvent;
use Illuminate\Support\Facades\Bus;

class TriggerDecisionEvents
{
    public function handle(ActivityDecisionApplied $event): void
    {
        $activity = $event->activity->loadMissing(['decision.events' => function ($q) {
            $q->wherePivot('active', true);
        }, 'contract', 'clientCase.client', 'user']);

        $decision = $activity->decision;
        if (! $decision) {
            return;
        }

        $events = $decision->events;
        if ($events->isEmpty()) {
            return;
        }

        // Sort by run_order when provided; otherwise keep natural order
        $sorted = $events->sortBy(function ($ev) {
            return $ev->pivot?->run_order ?? PHP_INT_MAX;
        })->values();

        $jobs = [];
        foreach ($sorted as $ev) {
            $base = is_array($ev->config ?? null) ? $ev->config : [];
            $pivotCfgRaw = $ev->pivot?->config ?? null;
            $pivotCfg = is_array($pivotCfgRaw)
                ? $pivotCfgRaw
                : (is_string($pivotCfgRaw) ? (json_decode($pivotCfgRaw, true) ?: []) : []);
            $effectiveConfig = array_replace_recursive($base, $pivotCfg);

            $jobs[] = new RunDecisionEvent(
                activityId: $activity->id,
                eventId: $ev->id,
                eventKey: (string) ($ev->key ?? ''),
                config: $effectiveConfig,
            );
        }

        // If any event has a finite run_order, chain to enforce order; else dispatch in parallel
        $hasOrder = $sorted->contains(fn ($ev) => $ev->pivot?->run_order !== null);

        // Run synchronously for local/dev/testing (or when debug is on) to ensure immediate effects without a queue worker
        $shouldRunSync = app()->environment(['local', 'development', 'dev', 'testing'])
            || (bool) config('app.debug')
            || config('queue.default') === 'sync';

        if ($hasOrder) {
            if ($shouldRunSync) {
                foreach ($jobs as $job) {
                    Bus::dispatchSync($job);
                }
            } else {
                Bus::chain($jobs)->dispatch();
            }
        } else {
            if ($shouldRunSync) {
                foreach ($jobs as $job) {
                    Bus::dispatchSync($job);
                }
            } else {
                foreach ($jobs as $job) {
                    dispatch($job);
                }
            }
        }
    }
}
