<?php

namespace App\Services\Intune;

use Illuminate\Support\Str;

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

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

    /**
     * @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'
        ));

        $configurationBlock = $this->buildConfigurationBlock($snapshot);

        if ($configurationBlock !== null) {
            $normalized['settings'][] = $configurationBlock;
        }

        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);
    }

    /**
     * @return array{type: string, title: string, entries: array<int, array<string, mixed>>}|null
     */
    private function buildConfigurationBlock(array $snapshot): ?array
    {
        $entries = [];
        $ignoredKeys = $this->ignoredKeys();

        foreach ($snapshot as $key => $value) {
            if (! is_string($key)) {
                continue;
            }

            if (in_array($key, $ignoredKeys, true)) {
                continue;
            }

            $entries[] = [
                'key' => Str::headline($key),
                'value' => $this->formatValue($value),
            ];
        }

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

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

    /**
     * @return array<int, string>
     */
    private function ignoredKeys(): array
    {
        return [
            '@odata.context',
            '@odata.type',
            'id',
            'version',
            'createdDateTime',
            'lastModifiedDateTime',
            'supportsScopeTags',
            'roleScopeTagIds',
            'assignments',
            'createdBy',
            'lastModifiedBy',
            'omaSettings',
            'settings',
            'settingsDelta',
            'displayName',
            'description',
            'name',
            'platform',
            'platforms',
            'technologies',
            'settingCount',
            'settingsCount',
            'templateReference',
        ];
    }

    private function formatValue(mixed $value): mixed
    {
        if (is_array($value)) {
            return json_encode($value, JSON_PRETTY_PRINT);
        }

        return $value;
    }
}
