<?php

declare(strict_types=1);

namespace App\Jobs;

use App\Jobs\Concerns\BridgesFailedOperationRun;
use App\Models\OperationRun;
use App\Models\EnvironmentReview;
use App\Services\OperationRunService;
use App\Services\EnvironmentReviews\EnvironmentReviewService;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\EnvironmentReviewStatus;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Throwable;

class ComposeEnvironmentReviewJob implements ShouldQueue
{
    use BridgesFailedOperationRun;
    use Queueable;

    public int $timeout = 240;

    public bool $failOnTimeout = true;

    public function __construct(
        public int $environmentReviewId,
        public int $operationRunId,
    ) {}

    public function handle(EnvironmentReviewService $service, OperationRunService $operationRuns): void
    {
        $review = EnvironmentReview::query()->with(['tenant', 'evidenceSnapshot.items'])->find($this->environmentReviewId);
        $operationRun = OperationRun::query()->find($this->operationRunId);

        if (! $review instanceof EnvironmentReview || ! $operationRun instanceof OperationRun || ! $review->tenant) {
            return;
        }

        $operationRuns->updateRun($operationRun, OperationRunStatus::Running->value, OperationRunOutcome::Pending->value);
        $review->update(['status' => EnvironmentReviewStatus::Draft->value]);

        try {
            $review = $service->compose($review);

            $summary = is_array($review->summary) ? $review->summary : [];

            $operationRuns->updateRun(
                $operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Succeeded->value,
                summaryCounts: [
                    'created' => 1,
                    'finding_count' => (int) ($summary['finding_count'] ?? 0),
                    'report_count' => (int) ($summary['report_count'] ?? 0),
                    'operation_count' => (int) ($summary['operation_count'] ?? 0),
                    'errors_recorded' => 0,
                ],
            );
        } catch (Throwable $throwable) {
            $review->update([
                'status' => EnvironmentReviewStatus::Failed->value,
                'summary' => array_merge(is_array($review->summary) ? $review->summary : [], [
                    'error' => $throwable->getMessage(),
                ]),
            ]);

            $operationRuns->updateRun(
                $operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Failed->value,
                failures: [
                    [
                        'code' => 'environment_review_compose.failed',
                        'message' => $throwable->getMessage(),
                    ],
                ],
            );

            throw $throwable;
        }
    }
}
