<?php

namespace App\Services\Intune;

use Illuminate\Support\Str;

class WindowsUpdateRingNormalizer implements PolicyTypeNormalizer
{
    public function __construct(
        private readonly DefaultPolicyNormalizer $defaultNormalizer,
    ) {}

    public function supports(string $policyType): bool
    {
        return $policyType === 'windowsUpdateRing';
    }

    /**
     * @return array{status: string, settings: array<int, array<string, mixed>>, settings_table?: array<string, mixed>, warnings: array<int, string>}
     */
    public function normalize(?array $snapshot, string $policyType, ?string $platform = null): array
    {
        $snapshot = $snapshot ?? [];
        $normalized = $this->defaultNormalizer->normalize($snapshot, $policyType, $platform);

        if ($snapshot === []) {
            return $normalized;
        }

        $normalized['settings'] = array_values(array_filter(
            $normalized['settings'],
            fn (array $block) => strtolower((string) ($block['title'] ?? '')) !== 'general'
        ));

        $normalized['settings'][] = $this->buildUpdateSettingsBlock($snapshot);
        $normalized['settings'][] = $this->buildUserExperienceBlock($snapshot);
        $normalized['settings'][] = $this->buildAdvancedOptionsBlock($snapshot);

        $normalized['settings'] = array_values(array_filter($normalized['settings']));

        return $normalized;
    }

    /**
     * @return array<string, mixed>
     */
    public function flattenForDiff(?array $snapshot, string $policyType, ?string $platform = null): array
    {
        $snapshot = $snapshot ?? [];
        $normalized = $this->normalize($snapshot, $policyType, $platform);

        return $this->defaultNormalizer->flattenNormalizedForDiff($normalized);
    }

    private function buildUpdateSettingsBlock(array $snapshot): ?array
    {
        $keys = [
            'allowWindows11Upgrade',
            'automaticUpdateMode',
            'featureUpdatesDeferralPeriodInDays',
            'featureUpdatesPaused',
            'featureUpdatesPauseExpiryDateTime',
            'qualityUpdatesDeferralPeriodInDays',
            'qualityUpdatesPaused',
            'qualityUpdatesPauseExpiryDateTime',
            'updateWindowsDeviceDriverExclusion',
        ];

        return $this->buildBlock('Update Settings', $snapshot, $keys);
    }

    private function buildUserExperienceBlock(array $snapshot): ?array
    {
        $keys = [
            'deadlineForFeatureUpdatesInDays',
            'deadlineForQualityUpdatesInDays',
            'deadlineGracePeriodInDays',
            'gracePeriodInDays',
            'restartActiveHoursStart',
            'restartActiveHoursEnd',
            'setActiveHours',
            'userPauseAccess',
            'userCheckAccess',
        ];

        return $this->buildBlock('User Experience', $snapshot, $keys);
    }

    private function buildAdvancedOptionsBlock(array $snapshot): ?array
    {
        $keys = [
            'deliveryOptimizationMode',
            'prereleaseFeatures',
            'servicingChannel',
            'microsoftUpdateServiceAllowed',
        ];

        return $this->buildBlock('Advanced Options', $snapshot, $keys);
    }

    private function buildBlock(string $title, array $snapshot, array $keys): ?array
    {
        $entries = [];

        foreach ($keys as $key) {
            if (array_key_exists($key, $snapshot)) {
                $entries[] = [
                    'key' => Str::headline($key),
                    'value' => $this->formatValue($snapshot[$key]),
                ];
            }
        }

        if ($entries === []) {
            return null;
        }

        return [
            'type' => 'keyValue',
            'title' => $title,
            'entries' => $entries,
        ];
    }

    private function formatValue(mixed $value): mixed
    {
        if (is_bool($value)) {
            return $value ? 'Yes' : 'No';
        }

        if (is_array($value)) {
            return json_encode($value, JSON_PRETTY_PRINT);
        }

        return $value;
    }
}
