<?php

declare(strict_types=1);

namespace App\Services\Baselines;

use App\Jobs\CompareBaselineToTenantJob;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\BaselineTenantAssignment;
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 BaselineCompareService
{
    public function __construct(
        private readonly OperationRunService $runs,
        private readonly BaselineFullContentRolloutGate $rolloutGate,
    ) {}

    /**
     * @return array{ok: bool, run?: OperationRun, reason_code?: string}
     */
    public function startCompare(
        Tenant $tenant,
        User $initiator,
        ?int $baselineSnapshotId = null,
    ): array {
        $assignment = BaselineTenantAssignment::query()
            ->where('workspace_id', $tenant->workspace_id)
            ->where('tenant_id', $tenant->getKey())
            ->first();

        if (! $assignment instanceof BaselineTenantAssignment) {
            return ['ok' => false, 'reason_code' => BaselineReasonCodes::COMPARE_NO_ASSIGNMENT];
        }

        $profile = BaselineProfile::query()->find($assignment->baseline_profile_id);

        if (! $profile instanceof BaselineProfile) {
            return ['ok' => false, 'reason_code' => BaselineReasonCodes::COMPARE_PROFILE_NOT_ACTIVE];
        }

        $hasExplicitSnapshotSelection = is_int($baselineSnapshotId) && $baselineSnapshotId > 0;
        $precondition = $this->validatePreconditions($profile, hasExplicitSnapshotSelection: $hasExplicitSnapshotSelection);

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

        $snapshotId = $baselineSnapshotId !== null ? (int) $baselineSnapshotId : 0;

        if ($snapshotId > 0) {
            $snapshot = BaselineSnapshot::query()
                ->where('workspace_id', (int) $profile->workspace_id)
                ->where('baseline_profile_id', (int) $profile->getKey())
                ->whereKey($snapshotId)
                ->first(['id']);

            if (! $snapshot instanceof BaselineSnapshot) {
                return ['ok' => false, 'reason_code' => BaselineReasonCodes::COMPARE_INVALID_SNAPSHOT];
            }
        } else {
            $snapshotId = (int) $profile->active_snapshot_id;
        }

        $profileScope = BaselineScope::fromJsonb(
            is_array($profile->scope_jsonb) ? $profile->scope_jsonb : null,
        );
        $overrideScope = $assignment->override_scope_jsonb !== null
            ? BaselineScope::fromJsonb(is_array($assignment->override_scope_jsonb) ? $assignment->override_scope_jsonb : null)
            : null;

        $effectiveScope = BaselineScope::effective($profileScope, $overrideScope);

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

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

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

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

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

    private function validatePreconditions(BaselineProfile $profile, bool $hasExplicitSnapshotSelection = false): ?string
    {
        if ($profile->status !== BaselineProfileStatus::Active) {
            return BaselineReasonCodes::COMPARE_PROFILE_NOT_ACTIVE;
        }

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

        if (! $hasExplicitSnapshotSelection && $profile->active_snapshot_id === null) {
            return BaselineReasonCodes::COMPARE_NO_ACTIVE_SNAPSHOT;
        }

        return null;
    }
}
