<?php

namespace App\Jobs;

use App\Models\Activity;
use App\Models\Event as DecisionEventModel;
use App\Services\DecisionEvents\ConditionEvaluator;
use App\Services\DecisionEvents\DecisionEventContext;
use App\Services\DecisionEvents\Registry;
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;

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

    public function __construct(
        public int $activityId,
        public int $eventId,
        public string $eventKey,
        public array $config = [],
    ) {}

    public function handle(): void
    {
        // Basic idempotency key per activity+event
        $idempotencyKey = sha1($this->activityId.'|'.$this->eventId.'|'.$this->eventKey);

        // Ensure log table record and uniqueness
        $exists = DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->first();
        if ($exists && ($exists->status ?? null) === 'succeeded') {
            return; // already processed successfully
        }
        try {
            $activity = Activity::with(['decision', 'contract', 'clientCase.client', 'user'])->findOrFail($this->activityId);

            if (! $exists) {
                DB::table('decision_event_logs')->insert([
                    'decision_id' => optional($activity->decision)->id,
                    'event_id' => $this->eventId,
                    'activity_id' => $this->activityId,
                    'handler' => $this->eventKey,
                    'status' => 'queued',
                    'idempotency_key' => $idempotencyKey,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                $exists = (object) ['status' => 'queued'];
            }

            DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
                'status' => 'running',
                'started_at' => now(),
                'updated_at' => now(),
            ]);
            $event = DecisionEventModel::findOrFail($this->eventId);

            $handler = Registry::resolve($this->eventKey);
            $context = new DecisionEventContext(
                activity: $activity,
                decision: $activity->decision,
                contract: $activity->contract,
                clientCase: $activity->clientCase,
                client: optional($activity->clientCase)->client,
                user: $activity->user,
            );

            // [2] Condition check — skip the event if any condition is not met
            $conditions = $this->config['conditions'] ?? [];
            if (! empty($conditions)) {
                $conditionsMet = app(ConditionEvaluator::class)->evaluate($conditions, $context);
                if (! $conditionsMet) {
                    DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
                        'status' => 'skipped',
                        'message' => 'Condition not met',
                        'finished_at' => now(),
                        'updated_at' => now(),
                    ]);

                    return;
                }
            }

            // [3] Resolve handler → handle()
            $handler->handle($context, $this->config);

            DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
                'status' => 'succeeded',
                'finished_at' => now(),
                'updated_at' => now(),
            ]);
        } catch (\Throwable $e) {
            DB::table('decision_event_logs')->where('idempotency_key', $idempotencyKey)->update([
                'status' => 'failed',
                'message' => substr($e->getMessage(), 0, 2000),
                'finished_at' => now(),
                'updated_at' => now(),
            ]);
            throw $e; // allow retry
        }
    }
}
