<?php

use App\Models\Policy;
use App\Models\ManagedEnvironment;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Intune\PolicySyncService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery\MockInterface;

uses(RefreshDatabase::class);

test('policy sync does not let enrollmentRestriction claim ESP items and reclassifies existing wrong rows', function () {
    $tenant = ManagedEnvironment::create([
        'managed_environment_id' => 'tenant-sync-collision',
        'name' => 'ManagedEnvironment Sync Collision',
        'metadata' => [],
        'is_current' => true,
    ]);

    $tenant->makeCurrent();
    ensureDefaultProviderConnection($tenant);

    // Simulate an older bug: ESP row was synced under enrollmentRestriction.
    $wrong = Policy::create([
        'managed_environment_id' => $tenant->id,
        'external_id' => 'esp-1',
        'policy_type' => 'enrollmentRestriction',
        'display_name' => 'ESP Misclassified',
        'platform' => 'all',
    ]);

    $this->mock(GraphClientInterface::class, function (MockInterface $mock) {
        $espPayload = [
            'id' => 'esp-1',
            'displayName' => 'Enrollment Status Page',
            '@odata.type' => '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration',
            'deviceEnrollmentConfigurationType' => 'windows10EnrollmentCompletionPageConfiguration',
        ];

        $mock->shouldReceive('listPolicies')
            ->andReturnUsing(function (string $policyType) use ($espPayload) {
                if ($policyType === 'enrollmentRestriction') {
                    // Shared endpoint can return ESP items if unfiltered.
                    return new GraphResponse(true, [$espPayload]);
                }

                if ($policyType === 'windowsEnrollmentStatusPage') {
                    return new GraphResponse(true, [$espPayload]);
                }

                return new GraphResponse(true, []);
            });
    });

    $service = app(PolicySyncService::class);

    $service->syncPolicies($tenant, [
        [
            'type' => 'enrollmentRestriction',
            'platform' => 'all',
            'filter' => null,
        ],
        [
            'type' => 'windowsEnrollmentStatusPage',
            'platform' => 'all',
            'filter' => null,
        ],
    ]);

    $wrong->refresh();

    expect($wrong->policy_type)->toBe('windowsEnrollmentStatusPage');
});

test('policy sync classifies ESP items without relying on Graph isof filter', function () {
    $tenant = ManagedEnvironment::create([
        'managed_environment_id' => 'tenant-sync-esp-no-filter',
        'name' => 'ManagedEnvironment Sync ESP No Filter',
        'metadata' => [],
        'is_current' => true,
    ]);

    $tenant->makeCurrent();
    ensureDefaultProviderConnection($tenant);

    $this->mock(GraphClientInterface::class, function (MockInterface $mock) {
        $payload = [
            [
                'id' => 'esp-1',
                'displayName' => 'Enrollment Status Page',
                '@odata.type' => '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration',
                'deviceEnrollmentConfigurationType' => 'windows10EnrollmentCompletionPageConfiguration',
            ],
            [
                'id' => 'restriction-1',
                'displayName' => 'Default Enrollment Restriction',
                '@odata.type' => '#microsoft.graph.deviceEnrollmentPlatformRestrictionConfiguration',
                'deviceEnrollmentConfigurationType' => 'deviceEnrollmentPlatformRestrictionConfiguration',
            ],
            [
                'id' => 'other-1',
                'displayName' => 'Other Enrollment Config',
                '@odata.type' => '#microsoft.graph.someOtherEnrollmentConfiguration',
                'deviceEnrollmentConfigurationType' => 'someOtherEnrollmentConfiguration',
            ],
        ];

        $mock->shouldReceive('listPolicies')
            ->andReturnUsing(function (string $policyType) use ($payload) {
                if (in_array($policyType, [
                    'enrollmentRestriction',
                    'windowsEnrollmentStatusPage',
                    'deviceEnrollmentPlatformRestrictionsConfiguration',
                ], true)) {
                    return new GraphResponse(true, $payload);
                }

                return new GraphResponse(true, []);
            });
    });

    $service = app(PolicySyncService::class);

    $service->syncPolicies($tenant, [
        [
            'type' => 'windowsEnrollmentStatusPage',
            'platform' => 'all',
            'filter' => null,
        ],
        [
            'type' => 'deviceEnrollmentPlatformRestrictionsConfiguration',
            'platform' => 'all',
            'filter' => null,
        ],
        [
            'type' => 'enrollmentRestriction',
            'platform' => 'all',
            'filter' => null,
        ],
    ]);

    $espIds = Policy::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('policy_type', 'windowsEnrollmentStatusPage')
        ->pluck('external_id')
        ->all();

    $restrictionIds = Policy::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('policy_type', 'enrollmentRestriction')
        ->orderBy('external_id')
        ->pluck('external_id')
        ->all();

    $platformRestrictionIds = Policy::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('policy_type', 'deviceEnrollmentPlatformRestrictionsConfiguration')
        ->orderBy('external_id')
        ->pluck('external_id')
        ->all();

    expect($espIds)->toMatchArray(['esp-1']);
    expect($platformRestrictionIds)->toMatchArray(['restriction-1']);
    expect($restrictionIds)->toMatchArray(['other-1']);
});

test('policy sync classifies enrollment configuration subtypes separately', function () {
    $tenant = ManagedEnvironment::create([
        'managed_environment_id' => 'tenant-sync-enrollment-subtypes',
        'name' => 'ManagedEnvironment Sync Enrollment Subtypes',
        'metadata' => [],
        'is_current' => true,
    ]);

    $tenant->makeCurrent();
    ensureDefaultProviderConnection($tenant);

    $this->mock(GraphClientInterface::class, function (MockInterface $mock) {
        $limitPayload = [
            'id' => 'limit-1',
            'displayName' => 'Enrollment Limit',
            '@odata.type' => '#microsoft.graph.deviceEnrollmentLimitConfiguration',
            'deviceEnrollmentConfigurationType' => 'deviceEnrollmentLimitConfiguration',
            'limit' => 5,
        ];

        $platformRestrictionsPayload = [
            'id' => 'platform-1',
            'displayName' => 'Platform Restrictions',
            '@odata.type' => '#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration',
            'deviceEnrollmentConfigurationType' => 'deviceEnrollmentPlatformRestrictionsConfiguration',
        ];

        $notificationPayload = [
            'id' => 'notify-1',
            'displayName' => 'Enrollment Notifications',
            '@odata.type' => '#microsoft.graph.deviceEnrollmentNotificationConfiguration',
            'deviceEnrollmentConfigurationType' => 'EnrollmentNotificationsConfiguration',
        ];

        $unfilteredPayload = [
            $limitPayload,
            $platformRestrictionsPayload,
            $notificationPayload,
        ];

        $mock->shouldReceive('listPolicies')
            ->andReturnUsing(function (string $policyType) use ($notificationPayload, $unfilteredPayload) {
                if ($policyType === 'deviceEnrollmentNotificationConfiguration') {
                    return new GraphResponse(true, [$notificationPayload]);
                }

                if (in_array($policyType, [
                    'enrollmentRestriction',
                    'deviceEnrollmentLimitConfiguration',
                    'deviceEnrollmentPlatformRestrictionsConfiguration',
                    'windowsEnrollmentStatusPage',
                ], true)) {
                    return new GraphResponse(true, $unfilteredPayload);
                }

                return new GraphResponse(true, []);
            });
    });

    $service = app(PolicySyncService::class);

    $service->syncPolicies($tenant, [
        ['type' => 'deviceEnrollmentLimitConfiguration', 'platform' => 'all', 'filter' => null],
        ['type' => 'deviceEnrollmentPlatformRestrictionsConfiguration', 'platform' => 'all', 'filter' => null],
        ['type' => 'deviceEnrollmentNotificationConfiguration', 'platform' => 'all', 'filter' => null],
        ['type' => 'enrollmentRestriction', 'platform' => 'all', 'filter' => null],
    ]);

    expect(Policy::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('policy_type', 'deviceEnrollmentLimitConfiguration')
        ->pluck('external_id')
        ->all())->toMatchArray(['limit-1']);

    expect(Policy::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('policy_type', 'deviceEnrollmentPlatformRestrictionsConfiguration')
        ->pluck('external_id')
        ->all())->toMatchArray(['platform-1']);

    expect(Policy::query()
        ->where('managed_environment_id', $tenant->id)
        ->where('policy_type', 'deviceEnrollmentNotificationConfiguration')
        ->pluck('external_id')
        ->all())->toMatchArray(['notify-1']);
});
