<?php

declare(strict_types=1);

use App\Models\ManagedEnvironment;
use App\Services\Tenants\TenantOperabilityService;
use App\Support\Tenants\TenantInteractionLane;
use App\Support\Tenants\TenantLifecycle;
use App\Support\Tenants\TenantOperabilityQuestion;
use App\Support\Tenants\TenantOperabilityReasonCode;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('returns lifecycle-aware operability decisions for every canonical tenant state', function (
    \Closure $tenantFactory,
    TenantLifecycle $expectedLifecycle,
    bool $canSelectAsContext,
    bool $canOperate,
    bool $canArchive,
    bool $canRestore,
    bool $canResumeOnboarding,
): void {
    $tenant = $tenantFactory();
    $decision = app(TenantOperabilityService::class)->decisionFor($tenant);

    expect($decision->lifecycle)->toBe($expectedLifecycle)
        ->and($decision->canViewTenantSurface)->toBeTrue()
        ->and($decision->canSelectAsContext)->toBe($canSelectAsContext)
        ->and($decision->canOperate)->toBe($canOperate)
        ->and($decision->canArchive)->toBe($canArchive)
        ->and($decision->canRestore)->toBe($canRestore)
        ->and($decision->canResumeOnboarding)->toBe($canResumeOnboarding)
        ->and($decision->canReferenceInWorkspaceMonitoring)->toBeTrue();
})->with([
    'draft' => [
        fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create(),
        TenantLifecycle::Draft,
        false,
        false,
        false,
        false,
        true,
    ],
    'onboarding' => [
        fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create(),
        TenantLifecycle::Onboarding,
        false,
        false,
        false,
        false,
        true,
    ],
    'active' => [
        fn (): ManagedEnvironment => ManagedEnvironment::factory()->active()->create(),
        TenantLifecycle::Active,
        true,
        true,
        true,
        false,
        false,
    ],
    'archived' => [
        fn (): ManagedEnvironment => ManagedEnvironment::factory()->archived()->create(),
        TenantLifecycle::Archived,
        false,
        false,
        false,
        true,
        false,
    ],
]);

it('returns structured selector outcomes for active and non-active tenants', function (
    \Closure $tenantFactory,
    bool $expectedAllowed,
    ?TenantOperabilityReasonCode $expectedReason,
): void {
    $tenant = $tenantFactory();

    $outcome = app(TenantOperabilityService::class)->outcomeFor(
        tenant: $tenant,
        question: TenantOperabilityQuestion::SelectorEligibility,
        lane: TenantInteractionLane::StandardActiveOperating,
    );

    expect($outcome->allowed)->toBe($expectedAllowed)
        ->and($outcome->reasonCode)->toBe($expectedReason);
})->with([
    'active-selector-eligible' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->active()->create(), true, null],
    'draft-selector-ineligible' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create(), false, TenantOperabilityReasonCode::SelectorIneligibleLifecycle],
    'onboarding-selector-ineligible' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create(), false, TenantOperabilityReasonCode::SelectorIneligibleLifecycle],
    'archived-selector-ineligible' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->archived()->create(), false, TenantOperabilityReasonCode::SelectorIneligibleLifecycle],
]);

it('keeps tenant-bound and canonical lanes viewable across all tenant lifecycles', function (
    \Closure $tenantFactory,
    TenantInteractionLane $lane,
): void {
    $tenant = $tenantFactory();

    $question = $lane === TenantInteractionLane::AdministrativeManagement
        ? TenantOperabilityQuestion::EnvironmentBoundViewability
        : TenantOperabilityQuestion::CanonicalLinkedRecordViewability;

    $outcome = app(TenantOperabilityService::class)->outcomeFor(
        tenant: $tenant,
        question: $question,
        lane: $lane,
    );

    expect($outcome->allowed)->toBeTrue()
        ->and($outcome->discoverable)->toBeTrue();
})->with([
    'draft-admin' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create(), TenantInteractionLane::AdministrativeManagement],
    'onboarding-admin' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create(), TenantInteractionLane::AdministrativeManagement],
    'archived-admin' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->archived()->create(), TenantInteractionLane::AdministrativeManagement],
    'onboarding-canonical' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create(), TenantInteractionLane::CanonicalWorkspaceRecord],
    'archived-canonical' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->archived()->create(), TenantInteractionLane::CanonicalWorkspaceRecord],
]);

it('returns wrong-lane reasons for questions asked in the wrong lane', function (): void {
    $tenant = ManagedEnvironment::factory()->active()->create();

    $outcome = app(TenantOperabilityService::class)->outcomeFor(
        tenant: $tenant,
        question: TenantOperabilityQuestion::ArchiveEligibility,
        lane: TenantInteractionLane::CanonicalWorkspaceRecord,
    );

    expect($outcome->allowed)->toBeFalse()
        ->and($outcome->reasonCode)->toBe(TenantOperabilityReasonCode::WrongLane);
});

it('returns lifecycle-safe primary management action keys', function (
    \Closure $tenantFactory,
    ?string $expectedActionKey,
): void {
    $tenant = $tenantFactory();

    expect(app(TenantOperabilityService::class)->primaryManagementActionKey($tenant))
        ->toBe($expectedActionKey);
})->with([
    'draft-primary' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create(), null],
    'onboarding-primary' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create(), null],
    'active-primary' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->active()->create(), 'archive'],
    'archived-primary' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->archived()->create(), 'restore'],
]);

it('can prefer onboarding as the primary management action for draft-like tenants', function (
    \Closure $tenantFactory,
): void {
    $tenant = $tenantFactory();

    expect(app(TenantOperabilityService::class)->primaryManagementActionKey($tenant, preferOnboarding: true))
        ->toBe('resume_onboarding');
})->with([
    'draft-prefers-onboarding' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create()],
    'onboarding-prefers-onboarding' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create()],
]);
