<?php

use App\Services\Intune\CompliancePolicyNormalizer;

it('groups compliance policy fields into structured blocks', function () {
    $normalizer = app(CompliancePolicyNormalizer::class);

    $snapshot = [
        '@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
        'passwordRequired' => true,
        'passwordMinimumLength' => 8,
        'defenderEnabled' => true,
        'bitLockerEnabled' => false,
        'osMinimumVersion' => '10.0.19045',
        'activeFirewallRequired' => true,
        'scheduledActionsForRule' => [
            [
                'ruleName' => 'Default rule',
                'scheduledActionConfigurations' => [
                    ['actionType' => 'notification'],
                ],
            ],
        ],
        'scheduledActionsForRule@odata.context' => 'https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceCompliancePolicies',
        'customSetting' => 'Custom value',
    ];

    $normalized = $normalizer->normalize($snapshot, 'deviceCompliancePolicy', 'windows');

    $settings = collect($normalized['settings']);

    $passwordBlock = $settings->firstWhere('title', 'Password & Access');
    expect($passwordBlock)->not->toBeNull();
    expect(collect($passwordBlock['rows'])->pluck('label')->all())
        ->toContain('Password required', 'Password minimum length');

    $additionalBlock = $settings->firstWhere('title', 'Additional Settings');
    expect($additionalBlock)->not->toBeNull();
    expect(collect($additionalBlock['rows'])->pluck('label')->all())
        ->toContain('Custom Setting');
    expect(collect($additionalBlock['rows'])->pluck('label')->all())
        ->not->toContain('Scheduled Actions For Rule');
    expect(collect($additionalBlock['rows'])->pluck('label')->all())
        ->not->toContain('Scheduled Actions For Rule@Odata.context');

    expect($settings->pluck('title')->all())->not->toContain('General');
});

it('flattens compliance noncompliance actions into a canonical diff signal', function () {
    $normalizer = app(CompliancePolicyNormalizer::class);

    $snapshot = [
        '@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
        'passwordRequired' => true,
        'scheduledActionsForRule' => [
            [
                'ruleName' => null,
                'scheduledActionConfigurations' => [
                    [
                        'actionType' => 'block',
                        'gracePeriodHours' => 240,
                        'notificationTemplateId' => '00000000-0000-0000-0000-000000000000',
                    ],
                    [
                        'actionType' => 'notification',
                        'gracePeriodHours' => 48,
                        'notificationTemplateId' => 'template-123',
                    ],
                    [
                        'actionType' => 'retire',
                        'gracePeriodHours' => 2664,
                        'notificationTemplateId' => 'template-retire',
                    ],
                ],
            ],
        ],
        'scheduledActionsForRule@odata.context' => 'https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceCompliancePolicies',
    ];

    $flat = $normalizer->flattenForDiff($snapshot, 'deviceCompliancePolicy', 'windows');

    expect($flat)->toHaveKey('Password & Access > Password required');
    expect($flat['Password & Access > Password required'])->toBeTrue();

    expect($flat)->toHaveKey('Actions for noncompliance > Mark device noncompliant > Grace period');
    expect($flat['Actions for noncompliance > Mark device noncompliant > Grace period'])->toBe('10 days (240 hours)');
    expect($flat)->toHaveKey('Actions for noncompliance > Mark device noncompliant > Notification template ID');
    expect($flat['Actions for noncompliance > Mark device noncompliant > Notification template ID'])->toBeNull();

    expect($flat)->toHaveKey('Actions for noncompliance > Send notification > Grace period');
    expect($flat['Actions for noncompliance > Send notification > Grace period'])->toBe('2 days (48 hours)');
    expect($flat['Actions for noncompliance > Send notification > Notification template ID'])->toBe('template-123');

    expect($flat)->toHaveKey('Actions for noncompliance > Add device to retire list > Grace period');
    expect($flat['Actions for noncompliance > Add device to retire list > Grace period'])->toBe('111 days (2664 hours)');
    expect($flat['Actions for noncompliance > Add device to retire list > Notification template ID'])->toBe('template-retire');

    expect(array_keys($flat))->not->toContain('scheduledActionsForRule');
    expect(array_keys($flat))->not->toContain('scheduledActionsForRule@odata.context');
});

it('ignores noncompliance action ids and ordering when flattening for diff', function () {
    $normalizer = app(CompliancePolicyNormalizer::class);

    $firstSnapshot = [
        '@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
        'scheduledActionsForRule' => [
            [
                'ruleName' => null,
                'scheduledActionConfigurations' => [
                    [
                        'id' => 'config-a',
                        'actionType' => 'notification',
                        'gracePeriodHours' => 48,
                        'notificationTemplateId' => 'template-b',
                    ],
                    [
                        'id' => 'config-b',
                        'actionType' => 'notification',
                        'gracePeriodHours' => 24,
                        'notificationTemplateId' => 'template-a',
                    ],
                ],
            ],
        ],
    ];

    $secondSnapshot = [
        '@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
        'scheduledActionsForRule' => [
            [
                'ruleName' => null,
                'scheduledActionConfigurations' => [
                    [
                        'id' => 'config-z',
                        'actionType' => 'notification',
                        'gracePeriodHours' => 24,
                        'notificationTemplateId' => 'template-a',
                    ],
                    [
                        'id' => 'config-y',
                        'actionType' => 'notification',
                        'gracePeriodHours' => 48,
                        'notificationTemplateId' => 'template-b',
                    ],
                ],
            ],
        ],
    ];

    $firstFlat = $normalizer->flattenForDiff($firstSnapshot, 'deviceCompliancePolicy', 'windows');
    $secondFlat = $normalizer->flattenForDiff($secondSnapshot, 'deviceCompliancePolicy', 'windows');

    expect($firstFlat)->toBe($secondFlat);
    expect($firstFlat)->toHaveKey('Actions for noncompliance > Send notification #1 > Grace period');
    expect($firstFlat)->toHaveKey('Actions for noncompliance > Send notification #2 > Grace period');
});
