<?php

declare(strict_types=1);

namespace App\Services\Baselines;

use App\Jobs\CaptureBaselineSnapshotJob;
use App\Models\BaselineProfile;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Models\User;
use App\Services\OperationRunService;
use App\Support\Baselines\BaselineCaptureMode;
use App\Support\Baselines\BaselineFullContentRolloutGate;
use App\Support\Baselines\BaselineProfileStatus;
use App\Support\Baselines\BaselineReasonCodes;
use App\Support\Baselines\BaselineScope;
use App\Support\OperationRunType;

final class BaselineCaptureService
{
    public function __construct(
        private readonly OperationRunService $runs,
        private readonly BaselineFullContentRolloutGate $rolloutGate,
    ) {}

    /**
     * @return array{ok: bool, run?: OperationRun, reason_code?: string}
     */
    public function startCapture(
        BaselineProfile $profile,
        Tenant $sourceTenant,
        User $initiator,
    ): array {
        $precondition = $this->validatePreconditions($profile, $sourceTenant);

        if ($precondition !== null) {
            return ['ok' => false, 'reason_code' => $precondition];
        }

        $effectiveScope = BaselineScope::fromJsonb(
            is_array($profile->scope_jsonb) ? $profile->scope_jsonb : null,
        );

        $captureMode = $profile->capture_mode instanceof BaselineCaptureMode
            ? $profile->capture_mode
            : BaselineCaptureMode::Opportunistic;

        $context = [
            'target_scope' => [
                'entra_tenant_id' => $sourceTenant->graphTenantId(),
                'entra_tenant_name' => (string) $sourceTenant->name,
            ],
            'baseline_profile_id' => (int) $profile->getKey(),
            'source_tenant_id' => (int) $sourceTenant->getKey(),
            'effective_scope' => $effectiveScope->toEffectiveScopeContext(),
            'capture_mode' => $captureMode->value,
        ];

        $run = $this->runs->ensureRunWithIdentity(
            tenant: $sourceTenant,
            type: OperationRunType::BaselineCapture->value,
            identityInputs: [
                'baseline_profile_id' => (int) $profile->getKey(),
            ],
            context: $context,
            initiator: $initiator,
        );

        if ($run->wasRecentlyCreated) {
            CaptureBaselineSnapshotJob::dispatch($run);
        }

        return ['ok' => true, 'run' => $run];
    }

    private function validatePreconditions(BaselineProfile $profile, Tenant $sourceTenant): ?string
    {
        if ($profile->status !== BaselineProfileStatus::Active) {
            return BaselineReasonCodes::CAPTURE_PROFILE_NOT_ACTIVE;
        }

        if ($profile->capture_mode === BaselineCaptureMode::FullContent && ! $this->rolloutGate->enabled()) {
            return BaselineReasonCodes::CAPTURE_ROLLOUT_DISABLED;
        }

        if ($sourceTenant->workspace_id === null) {
            return BaselineReasonCodes::CAPTURE_MISSING_SOURCE_TENANT;
        }

        if ((int) $sourceTenant->workspace_id !== (int) $profile->workspace_id) {
            return BaselineReasonCodes::CAPTURE_MISSING_SOURCE_TENANT;
        }

        return null;
    }
}
