<?php

namespace App\Services\Directory;

use App\Models\EntraGroup;
use App\Models\ManagedEnvironment;
use Illuminate\Support\Str;

class EntraGroupLabelResolver
{
    public function lookupOne(ManagedEnvironment $tenant, string $groupId): ?string
    {
        $labels = $this->lookupMany($tenant, [$groupId]);
        $lookupId = Str::isUuid($groupId) ? strtolower($groupId) : $groupId;

        return $labels[$lookupId] ?? null;
    }

    public function resolveOne(ManagedEnvironment $tenant, string $groupId): string
    {
        $labels = $this->resolveMany($tenant, [$groupId]);

        return $labels[$groupId] ?? self::formatLabel(null, $groupId);
    }

    /**
     * @param  array<int, string>  $groupIds
     * @return array<string, string>
     */
    public function resolveMany(ManagedEnvironment $tenant, array $groupIds): array
    {
        $groupIds = array_values(array_unique(array_filter($groupIds, fn ($id) => is_string($id) && $id !== '')));

        if ($groupIds === []) {
            return [];
        }

        $displayNames = $this->lookupMany($tenant, $groupIds);

        $labels = [];

        foreach ($groupIds as $groupId) {
            $lookupId = Str::isUuid($groupId) ? strtolower($groupId) : $groupId;
            $labels[$groupId] = self::formatLabel($displayNames[$lookupId] ?? null, $groupId);
        }

        return $labels;
    }

    /**
     * @param  array<int, string>  $groupIds
     * @param  array<string, string>  $fallbackLabels
     * @return array<string, array{display_name: ?string, resolved: bool}>
     */
    public function describeMany(ManagedEnvironment $tenant, array $groupIds, array $fallbackLabels = []): array
    {
        $groupIds = array_values(array_unique(array_filter($groupIds, fn ($id) => is_string($id) && $id !== '')));

        if ($groupIds === []) {
            return [];
        }

        $displayNames = $this->lookupMany($tenant, $groupIds);
        $descriptions = [];

        foreach ($groupIds as $groupId) {
            $lookupId = Str::isUuid($groupId) ? strtolower($groupId) : $groupId;
            $displayName = $displayNames[$lookupId] ?? ($fallbackLabels[$groupId] ?? null);

            $descriptions[$groupId] = [
                'display_name' => is_string($displayName) && $displayName !== '' ? $displayName : null,
                'resolved' => array_key_exists($lookupId, $displayNames),
            ];
        }

        return $descriptions;
    }

    /**
     * @param  array<int, string>  $groupIds
     * @return array<string, string> Map of groupId (lowercased UUID) => display_name
     */
    public function lookupMany(ManagedEnvironment $tenant, array $groupIds): array
    {
        $uuids = [];

        foreach ($groupIds as $groupId) {
            if (! is_string($groupId) || $groupId === '') {
                continue;
            }

            if (! Str::isUuid($groupId)) {
                continue;
            }

            $uuids[] = strtolower($groupId);
        }

        $uuids = array_values(array_unique($uuids));

        if ($uuids === []) {
            return [];
        }

        return EntraGroup::query()
            ->where('managed_environment_id', $tenant->getKey())
            ->whereIn('entra_id', $uuids)
            ->pluck('display_name', 'entra_id')
            ->mapWithKeys(fn (string $displayName, string $entraId) => [strtolower($entraId) => $displayName])
            ->all();
    }

    public static function formatLabel(?string $displayName, string $id): string
    {
        $name = filled($displayName) ? $displayName : 'Unresolved';

        return sprintf('%s (%s)', trim($name), self::shortToken($id));
    }

    private static function shortToken(string $id): string
    {
        $normalized = preg_replace('/[^a-zA-Z0-9]/', '', $id);

        if (! is_string($normalized) || $normalized === '') {
            return 'unknown';
        }

        if (mb_strlen($normalized) <= 8) {
            return $normalized;
        }

        return '…'.mb_substr($normalized, -8);
    }
}
