<?php

declare(strict_types=1);

use App\Models\ManagedEnvironment;
use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder;
use App\Support\Links\RequiredPermissionsLinks;
use App\Support\Providers\ProviderNextStepsRegistry;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Verification\VerificationAssistViewModelBuilder;
use App\Support\Verification\VerificationReportOverall;
use App\Support\Verification\VerificationReportWriter;
use Carbon\CarbonImmutable;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('derives blocked assist visibility and action availability from the stored diagnostics', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'external_id' => 'tenant-assist-blocked-a',
        'name' => 'Blocked ManagedEnvironment',
    ]);

    $permissionsBuilder = Mockery::mock(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class);
    $permissionsBuilder
        ->shouldReceive('build')
        ->twice()
        ->withArgs(function (ManagedEnvironment $passedTenant, array $filters) use ($tenant): bool {
            return (int) $passedTenant->getKey() === (int) $tenant->getKey()
                && ($filters['status'] ?? null) === 'all'
                && ($filters['type'] ?? null) === 'all'
                && ($filters['features'] ?? null) === []
                && ($filters['search'] ?? null) === '';
        })
        ->andReturn([
            'tenant' => [
                'id' => (int) $tenant->getKey(),
                'external_id' => (string) $tenant->external_id,
                'name' => (string) $tenant->name,
            ],
            'overview' => [
                'overall' => VerificationReportOverall::Blocked->value,
                'counts' => [
                    'missing_application' => 1,
                    'missing_delegated' => 1,
                    'present' => 3,
                    'error' => 0,
                ],
                'freshness' => [
                    'last_refreshed_at' => now()->toIso8601String(),
                    'is_stale' => false,
                ],
            ],
            'permissions' => [
                [
                    'key' => 'DeviceManagementConfiguration.Read.All',
                    'type' => 'application',
                    'description' => 'Read device configurations',
                    'features' => ['inventory'],
                    'status' => 'missing',
                    'details' => null,
                ],
                [
                    'key' => 'User.Read.All',
                    'type' => 'delegated',
                    'description' => 'Read users',
                    'features' => ['directory'],
                    'status' => 'missing',
                    'details' => null,
                ],
                [
                    'key' => 'Group.Read.All',
                    'type' => 'application',
                    'description' => 'Read groups',
                    'features' => ['directory'],
                    'status' => 'granted',
                    'details' => null,
                ],
            ],
            'copy' => [
                'application' => "DeviceManagementConfiguration.Read.All\nPolicy.Read.All",
                'delegated' => 'User.Read.All',
            ],
        ]);

    $builder = new VerificationAssistViewModelBuilder(
        $permissionsBuilder,
        app(ProviderNextStepsRegistry::class),
    );

    $report = VerificationReportWriter::build('provider.connection.check', [
        [
            'key' => 'permissions.admin_consent',
            'title' => 'Required application permissions',
            'status' => 'fail',
            'severity' => 'critical',
            'blocking' => true,
            'reason_code' => ProviderReasonCodes::ProviderConsentMissing,
            'message' => 'Grant admin consent before continuing.',
            'evidence' => [],
            'next_steps' => [],
        ],
    ]);

    $visibility = $builder->visibility($tenant, $report);
    $assist = $builder->build(
        tenant: $tenant,
        verificationReport: $report,
        verificationStatus: 'blocked',
        isVerificationStale: false,
        staleReason: null,
        canAccessProviderConnectionDiagnostics: true,
    );

    expect($visibility)->toMatchArray([
        'is_visible' => true,
        'reason' => 'permission_blocked',
    ]);

    expect($assist)->toMatchArray([
        'tenant' => [
            'id' => (int) $tenant->getKey(),
            'external_id' => (string) $tenant->external_id,
            'name' => (string) $tenant->name,
        ],
        'verification' => [
            'overall' => VerificationReportOverall::Blocked->value,
            'status' => 'blocked',
            'is_stale' => false,
            'stale_reason' => null,
        ],
        'copy' => [
            'application' => "DeviceManagementConfiguration.Read.All\nPolicy.Read.All",
            'delegated' => 'User.Read.All',
        ],
    ]);

    expect($assist['overview'])->toMatchArray([
        'overall' => VerificationReportOverall::Blocked->value,
        'counts' => [
            'missing_application' => 1,
            'missing_delegated' => 1,
            'present' => 3,
            'error' => 0,
        ],
    ]);

    expect($assist['overview']['freshness']['is_stale'])->toBeFalse();

    expect($assist['missing_permissions']['application'])->toHaveCount(1)
        ->and($assist['missing_permissions']['delegated'])->toHaveCount(1)
        ->and($assist['actions']['full_page'])->toMatchArray([
            'label' => 'Open full page',
            'url' => RequiredPermissionsLinks::requiredPermissions($tenant),
            'opens_in_new_tab' => true,
            'available' => true,
            'is_secondary' => true,
        ])
        ->and($assist['actions']['copy_application'])->toMatchArray([
            'label' => 'Copy missing application permissions',
            'available' => true,
        ])
        ->and($assist['actions']['copy_delegated'])->toMatchArray([
            'label' => 'Copy missing delegated permissions',
            'available' => true,
        ])
        ->and($assist['actions']['grant_admin_consent'])->toMatchArray([
            'label' => 'Grant admin consent',
            'url' => RequiredPermissionsLinks::adminConsentGuideUrl(),
            'opens_in_new_tab' => true,
            'available' => true,
        ])
        ->and($assist['fallback'])->toMatchArray([
            'has_incomplete_detail' => false,
            'message' => null,
        ]);

    expect($assist['actions']['manage_provider_connection'])->toMatchArray([
        'label' => 'Manage Provider Connections',
        'opens_in_new_tab' => true,
        'available' => true,
    ]);

    expect((string) $assist['actions']['manage_provider_connection']['url'])->toContain('/admin/provider-connections');
});

it('hides the assist when the verification report is ready and permission diagnostics are healthy', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'external_id' => 'tenant-assist-ready-a',
    ]);

    $permissionsBuilder = Mockery::mock(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class);
    $permissionsBuilder
        ->shouldReceive('build')
        ->once()
        ->andReturn([
            'tenant' => [
                'id' => (int) $tenant->getKey(),
                'external_id' => (string) $tenant->external_id,
                'name' => (string) $tenant->name,
            ],
            'overview' => [
                'overall' => VerificationReportOverall::Ready->value,
                'counts' => [
                    'missing_application' => 0,
                    'missing_delegated' => 0,
                    'present' => 15,
                    'error' => 0,
                ],
                'freshness' => [
                    'last_refreshed_at' => now()->toIso8601String(),
                    'is_stale' => false,
                ],
            ],
            'permissions' => [],
            'copy' => [
                'application' => '',
                'delegated' => '',
            ],
        ]);

    $builder = new VerificationAssistViewModelBuilder(
        $permissionsBuilder,
        app(ProviderNextStepsRegistry::class),
    );

    $report = VerificationReportWriter::build('provider.connection.check', [
        [
            'key' => 'provider.connection.check',
            'title' => 'Provider connection check',
            'status' => 'pass',
            'severity' => 'info',
            'blocking' => false,
            'reason_code' => 'ok',
            'message' => 'Connection is healthy.',
            'evidence' => [],
            'next_steps' => [],
        ],
    ]);

    expect($builder->visibility($tenant, $report))->toMatchArray([
        'is_visible' => false,
        'reason' => 'hidden_ready',
    ]);
});

it('builds degraded fallback messaging when permission detail is stale or incomplete', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'external_id' => 'tenant-assist-degraded-a',
    ]);

    $staleAt = CarbonImmutable::now()->subDays(45)->toIso8601String();

    $permissionsBuilder = Mockery::mock(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class);
    $permissionsBuilder
        ->shouldReceive('build')
        ->twice()
        ->andReturn([
            'tenant' => [
                'id' => (int) $tenant->getKey(),
                'external_id' => (string) $tenant->external_id,
                'name' => (string) $tenant->name,
            ],
            'overview' => [
                'overall' => VerificationReportOverall::NeedsAttention->value,
                'counts' => [
                    'missing_application' => 0,
                    'missing_delegated' => 0,
                    'present' => 14,
                    'error' => 1,
                ],
                'freshness' => [
                    'last_refreshed_at' => $staleAt,
                    'is_stale' => true,
                ],
            ],
            'permissions' => [
                [
                    'key' => 'DeviceManagementManagedDevices.Read.All',
                    'type' => 'application',
                    'description' => 'Stored row is incomplete',
                    'features' => ['inventory'],
                    'status' => 'error',
                    'details' => ['reason_code' => 'permission_denied'],
                ],
            ],
            'copy' => [
                'application' => '',
                'delegated' => '',
            ],
        ]);

    $builder = new VerificationAssistViewModelBuilder(
        $permissionsBuilder,
        app(ProviderNextStepsRegistry::class),
    );

    $report = VerificationReportWriter::build('provider.connection.check', [
        [
            'key' => 'permissions.admin_consent',
            'title' => 'Required application permissions',
            'status' => 'warn',
            'severity' => 'medium',
            'blocking' => false,
            'reason_code' => ProviderReasonCodes::ProviderPermissionRefreshFailed,
            'message' => 'Stored permission data needs review.',
            'evidence' => [],
            'next_steps' => [],
        ],
    ]);

    $visibility = $builder->visibility($tenant, $report);
    $assist = $builder->build(
        tenant: $tenant,
        verificationReport: $report,
        verificationStatus: 'needs_attention',
        isVerificationStale: true,
        staleReason: 'The selected provider connection has changed since this verification run.',
        canAccessProviderConnectionDiagnostics: false,
    );

    expect($visibility)->toMatchArray([
        'is_visible' => true,
        'reason' => 'permission_attention',
    ]);

    expect($assist['verification'])->toMatchArray([
        'overall' => VerificationReportOverall::NeedsAttention->value,
        'status' => 'needs_attention',
        'is_stale' => true,
        'stale_reason' => 'The selected provider connection has changed since this verification run.',
    ]);

    expect($assist['actions']['copy_application']['available'])->toBeFalse()
        ->and($assist['actions']['copy_delegated']['available'])->toBeFalse()
        ->and($assist['actions']['grant_admin_consent']['available'])->toBeFalse()
        ->and($assist['actions']['manage_provider_connection']['available'])->toBeFalse()
        ->and($assist['fallback']['has_incomplete_detail'])->toBeTrue()
        ->and($assist['fallback']['message'])->not->toBeNull();
});
