<?php

declare(strict_types=1);

namespace App\Jobs;

use App\Models\ManagedEnvironment;
use App\Services\OperationRunService;
use App\Services\PermissionPosture\FindingGeneratorContract;
use App\Support\OperationCatalog;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use RuntimeException;
use Throwable;

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

    public function __construct(
        public readonly int $tenantId,
        public readonly array $permissionComparison,
    ) {}

    public function handle(
        FindingGeneratorContract $generator,
        OperationRunService $operationRuns,
    ): void {
        $tenant = ManagedEnvironment::query()->find($this->tenantId);

        if (! $tenant instanceof ManagedEnvironment) {
            throw new RuntimeException('ManagedEnvironment not found: '.$this->tenantId);
        }

        // FR-016: Skip if tenant has no active provider connection
        if ($tenant->providerConnections()->count() === 0) {
            return;
        }

        $operationRun = $operationRuns->ensureRun(
            tenant: $tenant,
            type: OperationCatalog::TYPE_PERMISSION_POSTURE_CHECK,
            inputs: [
                'managed_environment_id' => $this->tenantId,
                'trigger' => 'health_check',
            ],
            initiator: null,
        );

        $operationRuns->updateRun(
            $operationRun,
            status: OperationRunStatus::Running->value,
            outcome: OperationRunOutcome::Pending->value,
        );

        try {
            $result = $generator->generate($tenant, $this->permissionComparison, $operationRun);

            $operationRuns->updateRun(
                $operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Succeeded->value,
                summaryCounts: [
                    'findings_created' => $result->findingsCreated,
                    'findings_resolved' => $result->findingsResolved,
                    'findings_reopened' => $result->findingsReopened,
                    'findings_unchanged' => $result->findingsUnchanged,
                    'errors_recorded' => $result->errorsRecorded,
                    'posture_score' => $result->postureScore,
                ],
            );
        } catch (Throwable $e) {
            $operationRuns->updateRun(
                $operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Failed->value,
                failures: [
                    [
                        'code' => 'permission_posture_check.failed',
                        'message' => $e->getMessage(),
                    ],
                ],
            );

            throw $e;
        }
    }
}
