<?php

namespace App\Jobs;

use App\Jobs\Middleware\TrackOperationRun;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Services\Intune\RbacHealthService;
use App\Services\OperationRunService;
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;

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

    public ?OperationRun $operationRun = null;

    public function __construct(
        public int $tenantId,
        public int $userId,
        ?OperationRun $operationRun = null,
    ) {
        $this->operationRun = $operationRun;
    }

    /**
     * @return array<int, object>
     */
    public function middleware(): array
    {
        return [new TrackOperationRun];
    }

    public function handle(
        RbacHealthService $rbacHealthService,
        OperationRunService $runs,
    ): void {
        $tenant = ManagedEnvironment::query()->find($this->tenantId);
        if (! $tenant instanceof ManagedEnvironment) {
            throw new RuntimeException('ManagedEnvironment not found.');
        }

        $user = User::query()->find($this->userId);
        if (! $user instanceof User) {
            throw new RuntimeException('User not found.');
        }

        $result = $rbacHealthService->check($tenant);

        if (! $this->operationRun instanceof OperationRun) {
            return;
        }

        $status = $result['status'] ?? 'error';
        $isHealthy = in_array($status, ['ok', 'configured', 'manual_assignment_required'], true);

        if ($isHealthy) {
            $runs->updateRun(
                $this->operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Succeeded->value,
            );

            return;
        }

        $runs->updateRun(
            $this->operationRun,
            status: OperationRunStatus::Completed->value,
            outcome: OperationRunOutcome::Failed->value,
            failures: [[
                'code' => 'rbac.health_check.failed',
                'reason_code' => $result['reason'] ?? 'unknown',
                'message' => sprintf('RBAC health check completed with status: %s', $status),
            ]],
        );
    }
}
