<?php

namespace App\Services\Graph;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class GroupResolver
{
    public function __construct(
        private readonly GraphClientInterface $graphClient,
    ) {}

    /**
     * Resolve group IDs to group objects with display names.
     *
     * Uses POST /directoryObjects/getByIds endpoint.
     * Missing IDs are marked as orphaned.
     *
     * @param  array  $groupIds  Array of group IDs to resolve
     * @param  string  $tenantId  Target tenant ID
     * @return array Keyed array: ['group-id' => ['id' => ..., 'displayName' => ..., 'orphaned' => bool]]
     */
    public function resolveGroupIds(array $groupIds, string $tenantId, array $options = []): array
    {
        if (empty($groupIds)) {
            return [];
        }

        // Create cache key
        $cacheKey = $this->getCacheKey($groupIds, $tenantId);

        return Cache::remember($cacheKey, 300, function () use ($groupIds, $tenantId, $options) {
            return $this->fetchAndResolveGroups($groupIds, $tenantId, $options);
        });
    }

    /**
     * Fetch groups from Graph API and resolve orphaned IDs.
     */
    private function fetchAndResolveGroups(array $groupIds, string $tenantId, array $options = []): array
    {
        try {
            $response = $this->graphClient->request(
                'POST',
                '/directoryObjects/getByIds',
                array_merge($options, [
                    'tenant' => $tenantId,
                    'json' => [
                        'ids' => array_values($groupIds),
                        'types' => ['group'],
                    ],
                ])
            );

            $resolvedGroups = $response->data['value'] ?? [];

            // Create result map
            $result = [];
            $resolvedIds = [];

            // Add resolved groups
            foreach ($resolvedGroups as $group) {
                $groupId = $group['id'];
                $resolvedIds[] = $groupId;
                $result[$groupId] = [
                    'id' => $groupId,
                    'displayName' => $group['displayName'] ?? null,
                    'orphaned' => false,
                ];
            }

            // Add orphaned groups (not in response)
            foreach ($groupIds as $groupId) {
                if (! in_array($groupId, $resolvedIds)) {
                    $result[$groupId] = [
                        'id' => $groupId,
                        'displayName' => null,
                        'orphaned' => true,
                    ];
                }
            }

            Log::debug('Resolved group IDs', [
                'managed_environment_id' => $tenantId,
                'requested' => count($groupIds),
                'resolved' => count($resolvedIds),
                'orphaned' => count($groupIds) - count($resolvedIds),
            ]);

            return $result;
        } catch (GraphException $e) {
            Log::warning('Failed to resolve group IDs', [
                'managed_environment_id' => $tenantId,
                'group_ids' => $groupIds,
                'error' => $e->getMessage(),
                'context' => $e->context,
            ]);

            // Return all as orphaned on failure
            $result = [];
            foreach ($groupIds as $groupId) {
                $result[$groupId] = [
                    'id' => $groupId,
                    'displayName' => null,
                    'orphaned' => true,
                ];
            }

            return $result;
        }
    }

    /**
     * Generate cache key for group resolution.
     */
    private function getCacheKey(array $groupIds, string $tenantId): string
    {
        sort($groupIds);

        return "groups:{$tenantId}:".md5(implode(',', $groupIds));
    }
}
