<?php

namespace App\Services\Drift\Normalizers;

use Illuminate\Support\Arr;

class AssignmentsNormalizer
{
    /**
     * @return array<int, array{key:string,include_exclude:string,target_type:string,target_id:string,filter_type:string,filter_id:?string,intent:?string,mode:?string}>
     */
    public function normalizeForDiff(mixed $assignments): array
    {
        if (! is_array($assignments)) {
            return [];
        }

        $rows = [];

        foreach ($assignments as $assignment) {
            if (! is_array($assignment)) {
                continue;
            }

            $target = $assignment['target'] ?? null;
            if (! is_array($target)) {
                continue;
            }

            $rawType = $target['@odata.type'] ?? null;
            $targetType = $this->normalizeOdataType(is_string($rawType) ? $rawType : '');

            $includeExclude = str_contains($targetType, 'exclusion') ? 'exclude' : 'include';
            $targetId = $this->extractTargetId($targetType, $target);

            if ($targetId === '') {
                continue;
            }

            $filterId = $target['deviceAndAppManagementAssignmentFilterId'] ?? null;
            $filterType = $target['deviceAndAppManagementAssignmentFilterType'] ?? 'none';

            $intent = $assignment['intent'] ?? null;
            $mode = $assignment['mode'] ?? null;

            $row = [
                'key' => implode('|', [
                    $includeExclude,
                    $targetType,
                    $targetId,
                ]),
                'include_exclude' => $includeExclude,
                'target_type' => $targetType,
                'target_id' => $targetId,
                'filter_type' => is_string($filterType) && $filterType !== '' ? strtolower(trim($filterType)) : 'none',
                'filter_id' => is_string($filterId) && $filterId !== '' ? $filterId : null,
                'intent' => is_string($intent) && $intent !== '' ? strtolower(trim($intent)) : null,
                'mode' => is_string($mode) && $mode !== '' ? strtolower(trim($mode)) : null,
            ];

            $rows[] = $row;
        }

        usort($rows, function (array $a, array $b): int {
            return strcmp($a['key'], $b['key']);
        });

        return array_values($rows);
    }

    private function normalizeOdataType(string $odataType): string
    {
        $value = trim($odataType);
        $value = ltrim($value, '#');

        if ($value === '') {
            return 'unknown';
        }

        if (str_contains($value, '.')) {
            $value = (string) strrchr($value, '.');
            $value = ltrim($value, '.');
        }

        return strtolower(trim($value));
    }

    /**
     * @param  array<string, mixed>  $target
     */
    private function extractTargetId(string $targetType, array $target): string
    {
        if (str_contains($targetType, 'alldevicesassignmenttarget')) {
            return 'all_devices';
        }

        if (str_contains($targetType, 'allusersassignmenttarget')) {
            return 'all_users';
        }

        $groupId = Arr::get($target, 'groupId');
        if (is_string($groupId) && $groupId !== '') {
            return $groupId;
        }

        $collectionId = Arr::get($target, 'collectionId');
        if (is_string($collectionId) && $collectionId !== '') {
            return $collectionId;
        }

        return '';
    }
}
