<?php

namespace App\Services\Intune;

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

    public function supports(string $policyType): bool
    {
        return in_array($policyType, ['settingsCatalogPolicy', 'endpointSecurityPolicy', 'securityBaselinePolicy'], true);
    }

    /**
     * @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
    {
        return $this->defaultNormalizer->normalize($snapshot, $policyType, $platform);
    }

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

        $map = [];

        if (isset($normalized['settings_table']['rows']) && is_array($normalized['settings_table']['rows'])) {
            $title = $normalized['settings_table']['title'] ?? 'Settings';
            $prefix = is_string($title) && $title !== '' ? $title.' > ' : '';
            $rows = $normalized['settings_table']['rows'];

            $baseLabels = array_values(array_filter(array_map(function (mixed $row): ?string {
                if (! is_array($row)) {
                    return null;
                }

                return $this->buildSettingsCatalogDiffLabel($row, includePath: false);
            }, $rows)));

            $labelCounts = array_count_values($baseLabels);

            foreach ($rows as $row) {
                if (! is_array($row)) {
                    continue;
                }

                $baseLabel = $this->buildSettingsCatalogDiffLabel($row, includePath: false);
                $label = $baseLabel;

                if (($labelCounts[$baseLabel] ?? 0) > 1) {
                    $path = $row['path'] ?? null;
                    $pathLabel = is_string($path) && $path !== '' ? $path : null;

                    $label = $this->buildSettingsCatalogDiffLabel($row, includePath: true);

                    if ($pathLabel !== null) {
                        $label .= ' @ '.$pathLabel;
                    }
                }

                $key = $prefix.$label;
                $map[$key] = $row['value'] ?? null;
            }
        }

        foreach ($normalized['settings'] ?? [] as $block) {
            if (! is_array($block)) {
                continue;
            }

            $title = $block['title'] ?? null;
            $prefix = is_string($title) && $title !== '' ? $title.' > ' : '';

            if (($block['type'] ?? null) === 'table') {
                foreach ($block['rows'] ?? [] as $row) {
                    if (! is_array($row)) {
                        continue;
                    }

                    $key = $prefix.($row['path'] ?? $row['label'] ?? 'entry');
                    $map[$key] = $row['value'] ?? null;
                }

                continue;
            }

            foreach ($block['entries'] ?? [] as $entry) {
                if (! is_array($entry)) {
                    continue;
                }

                $key = $prefix.($entry['key'] ?? 'entry');
                $map[$key] = $entry['value'] ?? null;
            }
        }

        return $map;
    }

    /**
     * @param  array<string, mixed>  $row
     */
    private function buildSettingsCatalogDiffLabel(array $row, bool $includePath): string
    {
        $category = $row['category'] ?? null;
        $definition = $row['definition'] ?? null;
        $definitionId = $row['definition_id'] ?? null;

        $label = is_string($definition) && $definition !== '' ? $definition : 'Setting';

        if ($includePath) {
            $path = $row['path'] ?? null;

            if (is_string($path) && $path !== '') {
                $label = $path;
            }

            if (
                is_string($label)
                && is_string($definitionId)
                && $definitionId !== ''
                && is_string($definition)
                && $definition !== ''
            ) {
                $parts = explode(' > ', $label);

                if ($parts !== [] && end($parts) === $definitionId) {
                    $parts[count($parts) - 1] = $definition;
                    $label = implode(' > ', $parts);
                }
            }
        }

        if (is_string($category) && $category !== '' && $category !== '-') {
            $label = $category.' > '.$label;
        }

        return $label;
    }
}
