<?php

namespace App\Modules\Settings\Rbac\Services;

use App\Modules\Settings\Rbac\Models\Permission;
use App\Modules\Settings\Rbac\Repositories\PermissionRepository;

final class TenantPermissionCatalogService
{
    public function __construct(
        private readonly PermissionRepository $permissions,
    ) {}

    /**
     * @return list<array{key: string, label: string, permissions: list<Permission>, assigned_count: int, total: int}>
     */
    public function matrixGroups(array $assignedIds): array
    {
        $assigned = array_flip(array_map('intval', $assignedIds));
        $bySlug = $this->permissions->allOrderedBySlug()->keyBy('slug');
        $groups = [];

        foreach (config('tenant-permission-catalog.groups', []) as $key => $meta) {
            $group = $this->configuredGroup((string) $key, (array) $meta, $bySlug, $assigned);
            if ($group !== null) {
                $groups[] = $group;
            }
        }

        $other = $this->otherPermissions($bySlug);
        if ($other !== []) {
            $groups[] = $this->groupData('other', __('permissions.groups.other'), $other, $assigned);
        }

        return $groups;
    }

    private function configuredGroup(string $key, array $meta, $bySlug, array $assigned): ?array
    {
        $permissions = [];
        foreach ((array) ($meta['abilities'] ?? []) as $slug) {
            $permission = $bySlug->get($slug);
            if ($permission instanceof Permission) {
                $permissions[] = $permission;
            }
        }

        return $permissions === [] ? null : $this->groupData(
            $key,
            __((string) ($meta['label_key'] ?? $key)),
            $permissions,
            $assigned,
        );
    }

    private function otherPermissions($bySlug): array
    {
        $catalog = collect(config('tenant-permission-catalog.groups', []))
            ->flatMap(fn (array $meta) => (array) ($meta['abilities'] ?? []))
            ->flip();

        return $bySlug
            ->reject(fn (Permission $permission, string $slug) => $catalog->has($slug)
                || str_starts_with($slug, 'attendance.registration_form'))
            ->values()
            ->all();
    }

    private function groupData(string $key, string $label, array $permissions, array $assigned): array
    {
        $assignedCount = count(array_filter(
            $permissions,
            fn (Permission $permission) => isset($assigned[(int) $permission->id]),
        ));

        return [
            'key' => $key,
            'label' => $label,
            'permissions' => $permissions,
            'assigned_count' => $assignedCount,
            'total' => count($permissions),
        ];
    }
}
