<?php

declare(strict_types=1);

namespace App\Jobs;

use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Services\EntraAdminRoles\EntraAdminRolesFindingGenerator;
use App\Services\EntraAdminRoles\EntraAdminRolesReportService;
use App\Services\OperationRunService;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OpsUx\RunFailureSanitizer;
use App\Support\Providers\ProviderConsentStatus;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Throwable;

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

    public function __construct(
        public readonly int $tenantId,
        public readonly int $workspaceId,
        public readonly ?int $initiatorUserId = null,
    ) {}

    public function handle(
        EntraAdminRolesReportService $reportService,
        EntraAdminRolesFindingGenerator $findingGenerator,
        OperationRunService $operationRuns,
    ): void {
        $tenant = ManagedEnvironment::query()->find($this->tenantId);

        if (! $tenant instanceof ManagedEnvironment) {
            return;
        }

        // FR-018: Skip tenants without active provider connection
        $hasConnection = ProviderConnection::query()
            ->where('managed_environment_id', $tenant->getKey())
            ->where('provider', 'microsoft')
            ->where('is_default', true)
            ->where('is_enabled', true)
            ->where('consent_status', ProviderConsentStatus::Granted->value)
            ->exists();

        if (! $hasConnection) {
            return;
        }

        $initiator = $this->initiatorUserId !== null
            ? User::query()->find($this->initiatorUserId)
            : null;

        $operationRun = $operationRuns->ensureRunWithIdentity(
            tenant: $tenant,
            type: 'entra.admin_roles.scan',
            identityInputs: [
                'managed_environment_id' => $this->tenantId,
                'trigger' => 'scan',
            ],
            context: [
                'workspace_id' => $this->workspaceId,
                'initiator_user_id' => $this->initiatorUserId,
            ],
            initiator: $initiator instanceof User ? $initiator : null,
        );

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

        try {
            $reportResult = $reportService->generate($tenant, $operationRun);

            $findingResult = $findingGenerator->generate($tenant, $reportResult->payload, $operationRun);

            $operationRuns->updateRun(
                $operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Succeeded->value,
                summaryCounts: [
                    'report_created' => $reportResult->created ? 1 : 0,
                    'report_deduped' => $reportResult->created ? 0 : 1,
                    'findings_created' => $findingResult->created,
                    'findings_resolved' => $findingResult->resolved,
                    'findings_reopened' => $findingResult->reopened,
                    'findings_unchanged' => $findingResult->unchanged,
                    'alert_events_produced' => $findingResult->alertEventsProduced,
                ],
            );
        } catch (Throwable $e) {
            $message = RunFailureSanitizer::sanitizeMessage($e->getMessage());
            $reasonCode = RunFailureSanitizer::normalizeReasonCode($e->getMessage());

            $operationRuns->updateRun(
                $operationRun,
                status: OperationRunStatus::Completed->value,
                outcome: OperationRunOutcome::Failed->value,
                failures: [[
                    'code' => 'entra.admin_roles.scan.failed',
                    'reason_code' => $reasonCode,
                    'message' => $message !== '' ? $message : 'Entra admin roles scan failed.',
                ]],
            );

            throw $e;
        }
    }
}
