<?php

declare(strict_types=1);

namespace App\Shared\Domain\Sidebar;

final class SidebarFilter
{
    /**
     * @param list<array{label:string, icon:string, roles?:list<string>, permission?:list<string>|string, items: list<array{label:string, to:string, icon:string, module?:string, roles?:list<string>, permission?:list<string>|string}>}> $sections
     * @param list<string>                                                                                                                                                                                                                 $activeModuleIds
     * @param list<string>                                                                                                                                                                                                                 $activeRoles
     * @param list<string>                                                                                                                                                                                                                 $activePermissions
     *
     * @return array{sections: list<array{label:string, icon:string, items: list<array{label:string, to:string, icon:string}>}>, disabledRoutes: list<string>}
     */
    public static function filter(array $sections, array $activeModuleIds, array $activeRoles = [], array $activePermissions = []): array
    {
        $outSections    = [];
        $disabledRoutes = [];

        foreach ($sections as $section) {
            // Gate de rôle au niveau section (ne pollue pas disabledRoutes : réservé au filtrage module).
            if (!self::rolesSatisfied($section['roles'] ?? null, $activeRoles)) {
                continue;
            }

            // Gate de permission au niveau section (RBAC fin).
            if (!self::permissionSatisfied($section['permission'] ?? null, $activePermissions)) {
                continue;
            }

            $items = [];
            foreach ($section['items'] as $item) {
                // Gate de rôle au niveau item.
                if (!self::rolesSatisfied($item['roles'] ?? null, $activeRoles)) {
                    continue;
                }

                // Gate de permission au niveau item (RBAC fin).
                if (!self::permissionSatisfied($item['permission'] ?? null, $activePermissions)) {
                    continue;
                }

                // Filtrage par module actif (pilote la redirection front via disabledRoutes).
                $module = $item['module'] ?? null;
                if (null !== $module && !in_array($module, $activeModuleIds, true)) {
                    $disabledRoutes[] = $item['to'];

                    continue;
                }

                $items[] = ['label' => $item['label'], 'to' => $item['to'], 'icon' => $item['icon']];
            }

            if ([] !== $items) {
                $outSections[] = ['label' => $section['label'], 'icon' => $section['icon'], 'items' => $items];
            }
        }

        return ['sections' => $outSections, 'disabledRoutes' => $disabledRoutes];
    }

    /**
     * @param null|list<string> $required
     * @param list<string>      $activeRoles
     */
    private static function rolesSatisfied(?array $required, array $activeRoles): bool
    {
        if (null === $required || [] === $required) {
            return true;
        }

        foreach ($required as $role) {
            if (in_array($role, $activeRoles, true)) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param null|list<string>|string $required          une permission (string) ou un ensemble (any)
     * @param list<string>             $activePermissions
     */
    private static function permissionSatisfied(array|string|null $required, array $activePermissions): bool
    {
        if (null === $required || '' === $required || [] === $required) {
            return true;
        }

        foreach ((array) $required as $code) {
            if (in_array($code, $activePermissions, true)) {
                return true;
            }
        }

        return false;
    }
}
