<?php

declare(strict_types=1);

namespace App\Services\Onboarding;

use App\Models\ManagedEnvironmentOnboardingSession;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Audit\WorkspaceAuditLogger;
use App\Support\Audit\AuditActionId;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class OnboardingDraftResolver
{
    public function __construct(
        private readonly OnboardingLifecycleService $lifecycleService,
        private readonly WorkspaceAuditLogger $auditLogger,
    ) {}

    /**
     * @throws AuthorizationException
     * @throws NotFoundHttpException
     */
    public function resolve(ManagedEnvironmentOnboardingSession|int|string $draft, User $user, Workspace $workspace): ManagedEnvironmentOnboardingSession
    {
        $draftId = $draft instanceof ManagedEnvironmentOnboardingSession
            ? (int) $draft->getKey()
            : (int) $draft;

        $resolvedDraft = ManagedEnvironmentOnboardingSession::query()
            ->with(['managedEnvironment', 'startedByUser', 'updatedByUser'])
            ->whereKey($draftId)
            ->first();

        if (! $resolvedDraft instanceof ManagedEnvironmentOnboardingSession) {
            throw new NotFoundHttpException;
        }

        if ((int) $resolvedDraft->workspace_id !== (int) $workspace->getKey()) {
            throw new NotFoundHttpException;
        }

        Gate::forUser($user)->authorize('view', $resolvedDraft);

        $resolvedDraft = $this->lifecycleService
            ->syncPersistedLifecycle($resolvedDraft)
            ->loadMissing(['managedEnvironment', 'startedByUser', 'updatedByUser']);

        $normalizedTenant = $this->lifecycleService->syncLinkedTenantAfterCancellation($resolvedDraft);

        if ($normalizedTenant !== null) {
            $this->auditLogger->logTenantLifecycleAction(
                tenant: $normalizedTenant,
                action: AuditActionId::TenantReturnedToDraft,
                actor: $user,
                context: [
                    'metadata' => [
                        'source' => 'onboarding_draft_resolver',
                        'onboarding_session_id' => (int) $resolvedDraft->getKey(),
                    ],
                ],
            );

            $resolvedDraft->setRelation('managedEnvironment', $normalizedTenant);
        }

        return $resolvedDraft;
    }

    /**
     * @throws AuthorizationException
     * @throws NotFoundHttpException
     */
    public function resolveForTrustedAction(ManagedEnvironmentOnboardingSession|int|string $draft, User $user, Workspace $workspace): ManagedEnvironmentOnboardingSession
    {
        return $this->resolve($draft, $user, $workspace);
    }

    /**
     * @return Collection<int, ManagedEnvironmentOnboardingSession>
     */
    public function resumableDraftsFor(User $user, Workspace $workspace): Collection
    {
        $drafts = ManagedEnvironmentOnboardingSession::query()
            ->with(['managedEnvironment', 'startedByUser', 'updatedByUser'])
            ->where('workspace_id', (int) $workspace->getKey())
            ->resumable()
            ->orderByDesc('updated_at')
            ->get();

        $resolvedDrafts = [];

        foreach ($drafts as $draft) {
            try {
                Gate::forUser($user)->authorize('view', $draft);
            } catch (AuthorizationException) {
                continue;
            }

            $resolvedDraft = $this->lifecycleService
                ->syncPersistedLifecycle($draft)
                ->loadMissing(['managedEnvironment', 'startedByUser', 'updatedByUser']);

            if (! $this->lifecycleService->canResumeDraft($resolvedDraft)) {
                continue;
            }

            $resolvedDrafts[] = $resolvedDraft;
        }

        return new Collection($resolvedDrafts);
    }
}
